diff --git a/.travis.yml b/.travis.yml
index 4df32e3..86f29d5 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,23 +1,29 @@
language: go
go:
- - 1.11.x
- - 1.12.x
- 1.13.x
- - tip
+ - master
os:
- linux
- osx
- windows
+arch:
+ - amd64
+ - arm64
+
matrix:
fast_finish: true
allow_failures:
- - go: tip
+ - go: master
exclude:
- os: windows
- go: tip
+ go: master
+ - os: windows
+ arch: arm64
+ - os: osx
+ arch: arm64
install:
- go get -d -v -t ./...
diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json
deleted file mode 100644
index f4ab75a..0000000
--- a/Godeps/Godeps.json
+++ /dev/null
@@ -1,40 +0,0 @@
-{
- "ImportPath": "github.com/adnanh/webhook",
- "GoVersion": "go1.9",
- "GodepVersion": "v79",
- "Deps": [
- {
- "ImportPath": "github.com/codegangsta/negroni",
- "Comment": "v0.2.0-151-g5bc66cf",
- "Rev": "5bc66cf1ad89af58511e07e108a31f219ed61012"
- },
- {
- "ImportPath": "github.com/ghodss/yaml",
- "Comment": "v1.0.0",
- "Rev": "0ca9ea5df5451ffdf184b4428c902747c2c11cd7"
- },
- {
- "ImportPath": "github.com/gorilla/mux",
- "Comment": "v1.5.0-2-gbdd5a5a",
- "Rev": "bdd5a5a1b0b489d297b73eb62b5f6328df198bfc"
- },
- {
- "ImportPath": "github.com/satori/go.uuid",
- "Comment": "v1.1.0-8-g5bf94b6",
- "Rev": "5bf94b69c6b68ee1b541973bb8e1144db23a194b"
- },
- {
- "ImportPath": "golang.org/x/sys/unix",
- "Rev": "ebfc5b4631820b793c9010c87fd8fef0f39eb082"
- },
- {
- "ImportPath": "gopkg.in/fsnotify.v1",
- "Comment": "v1.4.2",
- "Rev": "629574ca2a5df945712d3079857300b5e4da0236"
- },
- {
- "ImportPath": "gopkg.in/yaml.v2",
- "Rev": "eb3733d160e74a9c7e442f435eb3bea458e1d19f"
- }
- ]
-}
diff --git a/Godeps/Readme b/Godeps/Readme
deleted file mode 100644
index 4cdaa53..0000000
--- a/Godeps/Readme
+++ /dev/null
@@ -1,5 +0,0 @@
-This directory tree is generated automatically by godep.
-
-Please do not edit.
-
-See https://github.com/tools/godep for more information.
diff --git a/README.md b/README.md
index 1338a32..083c36f 100644
--- a/README.md
+++ b/README.md
@@ -26,7 +26,7 @@ If you don't have time to waste configuring, hosting, debugging and maintaining
# Getting started
## Installation
### Building from source
-To get started, first make sure you've properly set up your [Golang](http://golang.org/doc/install) environment and then run the
+To get started, first make sure you've properly set up your [Go](http://golang.org/doc/install) 1.12 or newer environment and then run
```bash
$ go get github.com/adnanh/webhook
```
@@ -77,12 +77,26 @@ By performing a simple HTTP GET or POST request to that endpoint, your specified
However, hook defined like that could pose a security threat to your system, because anyone who knows your endpoint, can send a request and execute your command. To prevent that, you can use the `"trigger-rule"` property for your hook, to specify the exact circumstances under which the hook would be triggered. For example, you can use them to add a secret that you must supply as a parameter in order to successfully trigger the hook. Please check out the [Hook rules page](docs/Hook-Rules.md) for detailed list of available rules and their usage.
+## Multipart Form Data
+[webhook][w] provides limited support the parsing of multipart form data.
+Multipart form data can contain two types of parts: values and files.
+All form _values_ are automatically added to the `payload` scope.
+Use the `parse-parameters-as-json` settings to parse a given value as JSON.
+All files are ignored unless they match one of the following criteria:
+
+1. The `Content-Type` header is `application/json`.
+1. The part is named in the `parse-parameters-as-json` setting.
+
+In either case, the given file part will be parsed as JSON and added to the `payload` map.
+
## Templates
[webhook][w] can parse the `hooks.json` input file as a Go template when given the `-template` [CLI parameter](docs/Webhook-Parameters.md). See the [Templates page](docs/Templates.md) for more details on template usage.
## Using HTTPS
[webhook][w] by default serves hooks using http. If you want [webhook][w] to serve secure content using https, you can use the `-secure` flag while starting [webhook][w]. Files containing a certificate and matching private key for the server must be provided using the `-cert /path/to/cert.pem` and `-key /path/to/key.pem` flags. If the certificate is signed by a certificate authority, the cert file should be the concatenation of the server's certificate followed by the CA's certificate.
+TLS version and cipher suite selection flags are available from the command line. To list available cipher suites, use the `-list-cipher-suites` flag. The `-tls-min-version` flag can be used with `-list-cipher-suites`.
+
## CORS Headers
If you want to set CORS headers, you can use the `-header name=value` flag while starting [webhook][w] to set the appropriate CORS headers that will be returned with each response.
diff --git a/cipher_suites.go b/cipher_suites.go
new file mode 100644
index 0000000..81db51f
--- /dev/null
+++ b/cipher_suites.go
@@ -0,0 +1,102 @@
+// 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.
+
+// Copied from Go 1.14 tip src/crypto/tls/cipher_suites.go
+
+package main
+
+import (
+ "crypto/tls"
+ "fmt"
+)
+
+// CipherSuite is a TLS cipher suite. Note that most functions in this package
+// accept and expose cipher suite IDs instead of this type.
+type CipherSuite struct {
+ ID uint16
+ Name string
+
+ // Supported versions is the list of TLS protocol versions that can
+ // negotiate this cipher suite.
+ SupportedVersions []uint16
+
+ // Insecure is true if the cipher suite has known security issues
+ // due to its primitives, design, or implementation.
+ Insecure bool
+}
+
+var (
+ supportedUpToTLS12 = []uint16{tls.VersionTLS10, tls.VersionTLS11, tls.VersionTLS12}
+ supportedOnlyTLS12 = []uint16{tls.VersionTLS12}
+ supportedOnlyTLS13 = []uint16{tls.VersionTLS13}
+)
+
+// CipherSuites returns a list of cipher suites currently implemented by this
+// package, excluding those with security issues, which are returned by
+// InsecureCipherSuites.
+//
+// The list is sorted by ID. Note that the default cipher suites selected by
+// this package might depend on logic that can't be captured by a static list.
+func CipherSuites() []*CipherSuite {
+ return []*CipherSuite{
+ {tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA, "TLS_RSA_WITH_3DES_EDE_CBC_SHA", supportedUpToTLS12, false},
+ {tls.TLS_RSA_WITH_AES_128_CBC_SHA, "TLS_RSA_WITH_AES_128_CBC_SHA", supportedUpToTLS12, false},
+ {tls.TLS_RSA_WITH_AES_256_CBC_SHA, "TLS_RSA_WITH_AES_256_CBC_SHA", supportedUpToTLS12, false},
+ {tls.TLS_RSA_WITH_AES_128_GCM_SHA256, "TLS_RSA_WITH_AES_128_GCM_SHA256", supportedOnlyTLS12, false},
+ {tls.TLS_RSA_WITH_AES_256_GCM_SHA384, "TLS_RSA_WITH_AES_256_GCM_SHA384", supportedOnlyTLS12, false},
+
+ {tls.TLS_AES_128_GCM_SHA256, "TLS_AES_128_GCM_SHA256", supportedOnlyTLS13, false},
+ {tls.TLS_AES_256_GCM_SHA384, "TLS_AES_256_GCM_SHA384", supportedOnlyTLS13, false},
+ {tls.TLS_CHACHA20_POLY1305_SHA256, "TLS_CHACHA20_POLY1305_SHA256", supportedOnlyTLS13, false},
+
+ {tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", supportedUpToTLS12, false},
+ {tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", supportedUpToTLS12, false},
+ {tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", supportedUpToTLS12, false},
+ {tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", supportedUpToTLS12, false},
+ {tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", supportedUpToTLS12, false},
+ {tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", supportedOnlyTLS12, false},
+ {tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", supportedOnlyTLS12, false},
+ {tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", supportedOnlyTLS12, false},
+ {tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", supportedOnlyTLS12, false},
+
+ // go1.14
+ // {tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", supportedOnlyTLS12, false},
+ // {tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", supportedOnlyTLS12, false},
+ }
+}
+
+// InsecureCipherSuites returns a list of cipher suites currently implemented by
+// this package and which have security issues.
+//
+// Most applications should not use the cipher suites in this list, and should
+// only use those returned by CipherSuites.
+func InsecureCipherSuites() []*CipherSuite {
+ // RC4 suites are broken because RC4 is.
+ // CBC-SHA256 suites have no Lucky13 countermeasures.
+ return []*CipherSuite{
+ {tls.TLS_RSA_WITH_RC4_128_SHA, "TLS_RSA_WITH_RC4_128_SHA", supportedUpToTLS12, true},
+ {tls.TLS_RSA_WITH_AES_128_CBC_SHA256, "TLS_RSA_WITH_AES_128_CBC_SHA256", supportedOnlyTLS12, true},
+ {tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA", supportedUpToTLS12, true},
+ {tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA, "TLS_ECDHE_RSA_WITH_RC4_128_SHA", supportedUpToTLS12, true},
+ {tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", supportedOnlyTLS12, true},
+ {tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", supportedOnlyTLS12, true},
+ }
+}
+
+// CipherSuiteName returns the standard name for the passed cipher suite ID
+// (e.g. "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"), or a fallback representation
+// of the ID value if the cipher suite is not implemented by this package.
+func CipherSuiteName(id uint16) string {
+ for _, c := range CipherSuites() {
+ if c.ID == id {
+ return c.Name
+ }
+ }
+ for _, c := range InsecureCipherSuites() {
+ if c.ID == id {
+ return c.Name
+ }
+ }
+ return fmt.Sprintf("0x%04X", id)
+}
diff --git a/docs/Hook-Definition.md b/docs/Hook-Definition.md
index 14c17f6..a963ef3 100644
--- a/docs/Hook-Definition.md
+++ b/docs/Hook-Definition.md
@@ -10,6 +10,7 @@ Hooks are defined as JSON objects. Please note that in order to be considered va
* `response-headers` - specifies the list of headers in format `{"name": "X-Example-Header", "value": "it works"}` that will be returned in HTTP response for the hook
* `success-http-response-code` - specifies the HTTP status code to be returned upon success
* `incoming-payload-content-type` - sets the `Content-Type` of the incoming HTTP request (ie. `application/json`); useful when the request lacks a `Content-Type` or sends an erroneous value
+ * `http-methods` - a list of allowed HTTP methods, such as `POST` and `GET`
* `include-command-output-in-response` - boolean whether webhook should wait for the command to finish and return the raw output as a response to the hook initiator. If the command fails to execute or encounters any errors while executing the response will result in 500 Internal Server Error HTTP status code, otherwise the 200 OK status code will be returned.
* `include-command-output-in-response-on-error` - boolean whether webhook should include command stdout & stderror as a response in failed executions. It only works if `include-command-output-in-response` is set to `true`.
* `parse-parameters-as-json` - specifies the list of arguments that contain JSON strings. These parameters will be decoded by webhook and you can access them like regular objects in rules and `pass-arguments-to-command`.
diff --git a/docs/Hook-Examples.md b/docs/Hook-Examples.md
index f2cab8c..23896a7 100644
--- a/docs/Hook-Examples.md
+++ b/docs/Hook-Examples.md
@@ -287,12 +287,12 @@ __Not recommended in production due to low security__
]
```
-# JIRA Webhooks
+## JIRA Webhooks
[Guide by @perfecto25](https://sites.google.com/site/mrxpalmeiras/notes/jira-webhooks)
-# Pass File-to-command sample
+## Pass File-to-command sample
-## Webhook configuration
+### Webhook configuration
[
@@ -315,7 +315,7 @@ __Not recommended in production due to low security__
]
-## Sample client usage
+### Sample client usage
Store the following file as `testRequest.json`.
@@ -424,3 +424,97 @@ Travis sends webhooks as `payload=`, so the payload needs to be par
}
]
```
+
+## XML Payload
+
+Given the following payload:
+
+```xml
+
+
+
+
+
+
+ Hello!!
+
+
+```
+
+```json
+[
+ {
+ "id": "deploy",
+ "execute-command": "/root/my-server/deployment.sh",
+ "command-working-directory": "/root/my-server",
+ "trigger-rule": {
+ "and": [
+ {
+ "match": {
+ "type": "value",
+ "parameter": {
+ "source": "payload",
+ "name": "app.users.user.0.-name"
+ },
+ "value": "Jeff"
+ }
+ },
+ {
+ "match": {
+ "type": "value",
+ "parameter": {
+ "source": "payload",
+ "name": "app.messages.message.#text"
+ },
+ "value": "Hello!!"
+ }
+ },
+ ],
+ }
+ }
+]
+```
+
+## Multipart Form Data
+
+Example of a [Plex Media Server webhook](https://support.plex.tv/articles/115002267687-webhooks/).
+The Plex Media Server will send two parts: payload and thumb.
+We only care about the payload part.
+
+```json
+[
+ {
+ "id": "plex",
+ "execute-command": "play-command.sh",
+ "parse-parameters-as-json": [
+ {
+ "source": "payload",
+ "name": "payload"
+ }
+ ],
+ "trigger-rule":
+ {
+ "match":
+ {
+ "type": "value",
+ "parameter": {
+ "source": "payload",
+ "name": "payload.event"
+ },
+ "value": "media.play"
+ }
+ }
+ }
+]
+
+```
+
+Each part of a multipart form data body will have a `Content-Disposition` header.
+Some example headers:
+
+```
+Content-Disposition: form-data; name="payload"
+Content-Disposition: form-data; name="thumb"; filename="thumb.jpg"
+```
+
+We key off of the `name` attribute in the `Content-Disposition` value.
diff --git a/docs/Hook-Rules.md b/docs/Hook-Rules.md
index 52947aa..e1f92f6 100644
--- a/docs/Hook-Rules.md
+++ b/docs/Hook-Rules.md
@@ -186,7 +186,60 @@ For the regex syntax, check out
}
```
-### 4. Match Whitelisted IP range
+Note that if multiple signatures were passed via a comma separated string, each
+will be tried unless a match is found. For example:
+
+```
+X-Hub-Signature: sha1=the-first-signature,sha1=the-second-signature
+```
+
+### 4. Match payload-hash-sha256
+```json
+{
+ "match":
+ {
+ "type": "payload-hash-sha256",
+ "secret": "yoursecret",
+ "parameter":
+ {
+ "source": "header",
+ "name": "X-Signature"
+ }
+ }
+}
+```
+
+Note that if multiple signatures were passed via a comma separated string, each
+will be tried unless a match is found. For example:
+
+```
+X-Hub-Signature: sha256=the-first-signature,sha256=the-second-signature
+```
+
+### 5. Match payload-hash-sha512
+```json
+{
+ "match":
+ {
+ "type": "payload-hash-sha512",
+ "secret": "yoursecret",
+ "parameter":
+ {
+ "source": "header",
+ "name": "X-Signature"
+ }
+ }
+}
+```
+
+Note that if multiple signatures were passed via a comma separated string, each
+will be tried unless a match is found. For example:
+
+```
+X-Hub-Signature: sha512=the-first-signature,sha512=the-second-signature
+```
+
+### 6. Match Whitelisted IP range
The IP can be IPv4- or IPv6-formatted, using [CIDR notation](https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing#CIDR_blocks). To match a single IP address only, use `/32`.
@@ -200,7 +253,7 @@ The IP can be IPv4- or IPv6-formatted, using [CIDR notation](https://en.wikipedi
}
```
-### 5. Match scalr-signature
+### 7. Match scalr-signature
The trigger rule checks the scalr signature and also checks that the request was signed less than 5 minutes before it was received.
A unqiue signing key is generated for each webhook endpoint URL you register in Scalr.
diff --git a/docs/Referencing-Request-Values.md b/docs/Referencing-Request-Values.md
index e85c3f2..a76e57f 100644
--- a/docs/Referencing-Request-Values.md
+++ b/docs/Referencing-Request-Values.md
@@ -68,6 +68,34 @@ There are four types of request values:
If the payload contains a key with the specified name "commits.0.commit.id", then the value of that key has priority over the dot-notation referencing.
+3. XML Payload
+
+ Referencing XML payload parameters is much like the JSON examples above, but XML is more complex.
+ Element attributes are prefixed by a hyphen (`-`).
+ Element values are prefixed by a pound (`#`).
+
+ Take the following XML payload:
+
+ ```xml
+
+
+
+
+
+
+ Hello!!
+
+
+ ```
+
+ To access a given `user` element, you must treat them as an array.
+ So `app.users.user.0.name` yields `Jeff`.
+
+ Since there's only one `message` tag, it's not treated as an array.
+ So `app.messages.message.id` yields `1`.
+
+ To access the text within the `message` tag, you would use: `app.messages.message.#text`.
+
If you are referencing values for environment, you can use `envname` property to set the name of the environment variable like so
```json
{
@@ -98,4 +126,4 @@ and for query variables you can use
{
"source": "entire-query"
}
-```
\ No newline at end of file
+```
diff --git a/docs/Webhook-Parameters.md b/docs/Webhook-Parameters.md
index ab51bea..bfd883f 100644
--- a/docs/Webhook-Parameters.md
+++ b/docs/Webhook-Parameters.md
@@ -3,36 +3,60 @@
Usage of webhook:
-cert string
path to the HTTPS certificate pem file (default "cert.pem")
+ -cipher-suites string
+ comma-separated list of supported TLS cipher suites
+ -debug
+ show debug output
-header value
response header to return, specified in format name=value, use multiple times to set multiple headers
-hooks value
path to the json file containing defined hooks the webhook should serve, use multiple times to load from different files
-hotreload
watch hooks file for changes and reload them automatically
+ -http-methods string
+ globally restrict allowed HTTP methods; separate methods with comma
-ip string
ip the webhook should serve hooks on (default "0.0.0.0")
-key string
path to the HTTPS certificate private key pem file (default "key.pem")
+ -list-cipher-suites
+ list available TLS cipher suites
+ -logfile string
+ send log output to a file; implicitly enables verbose logging
-nopanic
do not panic if hooks cannot be loaded when webhook is not running in verbose mode
+ -pidfile string
+ create PID file at the given path
-port int
port the webhook should serve hooks on (default 9000)
-secure
use HTTPS instead of HTTP
+ -setgid int
+ set group ID after opening listening port; must be used with setuid
+ -setuid int
+ set user ID after opening listening port; must be used with setgid
-template
parse hooks file as a Go template
+ -tls-min-version string
+ minimum TLS version (1.0, 1.1, 1.2, 1.3) (default "1.2")
-urlprefix string
url prefix to use for served hooks (protocol://yourserver:port/PREFIX/:hook-id) (default "hooks")
-verbose
show verbose output
-version
display webhook version and quit
+ -x-request-id
+ use X-Request-Id header, if present, as request ID
+ -x-request-id-limit int
+ truncate X-Request-Id header to limit; default no limit
```
Use any of the above specified flags to override their default behavior.
# Live reloading hooks
-If you are running an OS that supports USR1 signal, you can use it to trigger hooks reload from hooks file, without restarting the webhook instance.
+If you are running an OS that supports the HUP or USR1 signal, you can use it to trigger hooks reload from hooks file, without restarting the webhook instance.
```bash
kill -USR1 webhookpid
-```
\ No newline at end of file
+
+kill -HUP webhookpid
+```
diff --git a/droppriv_nope.go b/droppriv_nope.go
new file mode 100644
index 0000000..3c6a518
--- /dev/null
+++ b/droppriv_nope.go
@@ -0,0 +1,12 @@
+// +build linux windows
+
+package main
+
+import (
+ "errors"
+ "runtime"
+)
+
+func dropPrivileges(uid, gid int) error {
+ return errors.New("setuid and setgid not supported on " + runtime.GOOS)
+}
diff --git a/droppriv_unix.go b/droppriv_unix.go
new file mode 100644
index 0000000..c292e7d
--- /dev/null
+++ b/droppriv_unix.go
@@ -0,0 +1,21 @@
+// +build !windows,!linux
+
+package main
+
+import (
+ "syscall"
+)
+
+func dropPrivileges(uid, gid int) error {
+ err := syscall.Setgid(gid)
+ if err != nil {
+ return err
+ }
+
+ err = syscall.Setuid(uid)
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
diff --git a/go.mod b/go.mod
new file mode 100644
index 0000000..bc7efb7
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,19 @@
+module github.com/adnanh/webhook
+
+go 1.13
+
+require (
+ github.com/clbanning/mxj v1.8.4
+ github.com/dustin/go-humanize v1.0.0
+ github.com/fsnotify/fsnotify v1.4.7 // indirect
+ github.com/ghodss/yaml v1.0.0
+ github.com/go-chi/chi v4.0.2+incompatible
+ github.com/gofrs/uuid v3.2.0+incompatible
+ github.com/gorilla/mux v1.7.3
+ github.com/kr/pretty v0.1.0 // indirect
+ golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 // indirect
+ golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8
+ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
+ gopkg.in/fsnotify.v1 v1.4.2
+ gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7 // indirect
+)
diff --git a/go.sum b/go.sum
new file mode 100644
index 0000000..a9a5f57
--- /dev/null
+++ b/go.sum
@@ -0,0 +1,34 @@
+github.com/clbanning/mxj v1.8.4 h1:HuhwZtbyvyOw+3Z1AowPkU87JkJUSv751ELWaiTpj8I=
+github.com/clbanning/mxj v1.8.4/go.mod h1:BVjHeAH+rl9rs6f+QIpeRl0tfu10SXn1pUSa5PVGJng=
+github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
+github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
+github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
+github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
+github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
+github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+github.com/go-chi/chi v4.0.2+incompatible h1:maB6vn6FqCxrpz4FqWdh4+lwpyZIQS7YEAUcHlgXVRs=
+github.com/go-chi/chi v4.0.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
+github.com/gofrs/uuid v3.2.0+incompatible h1:y12jRkkFxsd7GpqdSZ+/KCs/fJbqpEXSGd4+jfEaewE=
+github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
+github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw=
+github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
+github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
+github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 h1:efeOvDhwQ29Dj3SdAV/MJf8oukgn+8D8WgaCaRMchF8=
+golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8 h1:JA8d3MPx/IToSyXZG/RhwYEtfrKO1Fxrqe8KrkiLXKM=
+golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/fsnotify.v1 v1.4.2 h1:AwZiD/bIUttYJ+n/k1UwlSUsM+VSE6id7UAnSKqQ+Tc=
+gopkg.in/fsnotify.v1 v1.4.2/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
+gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7 h1:+t9dhfO+GNOIGJof6kPOAenx7YgrZMTdRPV+EsnPabk=
+gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
diff --git a/hook/hook.go b/internal/hook/hook.go
similarity index 78%
rename from hook/hook.go
rename to internal/hook/hook.go
index d8711b3..0573a3f 100644
--- a/hook/hook.go
+++ b/internal/hook/hook.go
@@ -5,11 +5,14 @@ import (
"crypto/hmac"
"crypto/sha1"
"crypto/sha256"
+ "crypto/sha512"
+ "crypto/subtle"
"encoding/base64"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
+ "hash"
"io/ioutil"
"log"
"math"
@@ -47,15 +50,43 @@ const (
EnvNamespace string = "HOOK_"
)
+// ParameterNodeError describes an error walking a parameter node.
+type ParameterNodeError struct {
+ key string
+}
+
+func (e *ParameterNodeError) Error() string {
+ if e == nil {
+ return ""
+ }
+ return fmt.Sprintf("parameter node not found: %s", e.key)
+}
+
+// IsParameterNodeError returns whether err is of type ParameterNodeError.
+func IsParameterNodeError(err error) bool {
+ switch err.(type) {
+ case *ParameterNodeError:
+ return true
+ default:
+ return false
+ }
+}
+
// SignatureError describes an invalid payload signature passed to Hook.
type SignatureError struct {
- Signature string
+ Signature string
+ Signatures []string
}
func (e *SignatureError) Error() string {
if e == nil {
return ""
}
+
+ if e.Signatures != nil {
+ return fmt.Sprintf("invalid payload signatures %s", e.Signatures)
+ }
+
return fmt.Sprintf("invalid payload signature %s", e.Signature)
}
@@ -95,25 +126,67 @@ func (e *ParseError) Error() string {
return e.Err.Error()
}
+// ExtractCommaSeparatedValues will extract the values matching the key.
+func ExtractCommaSeparatedValues(source, prefix string) []string {
+ parts := strings.Split(source, ",")
+ values := make([]string, 0)
+ for _, part := range parts {
+ if strings.HasPrefix(part, prefix) {
+ values = append(values, strings.TrimPrefix(part, prefix))
+ }
+ }
+
+ return values
+}
+
+// ExtractSignatures will extract all the signatures from the source.
+func ExtractSignatures(source, prefix string) []string {
+ // If there are multiple possible matches, let the comma seperated extractor
+ // do it's work.
+ if strings.Contains(source, ",") {
+ return ExtractCommaSeparatedValues(source, prefix)
+ }
+
+ // There were no commas, so just trim the prefix (if it even exists) and
+ // pass it back.
+ return []string{
+ strings.TrimPrefix(source, prefix),
+ }
+}
+
+// ValidateMAC will verify that the expected mac for the given hash will match
+// the one provided.
+func ValidateMAC(payload []byte, mac hash.Hash, signatures []string) (string, error) {
+ // Write the payload to the provided hash.
+ _, err := mac.Write(payload)
+ if err != nil {
+ return "", err
+ }
+
+ expectedMAC := hex.EncodeToString(mac.Sum(nil))
+
+ for _, signature := range signatures {
+ if hmac.Equal([]byte(signature), []byte(expectedMAC)) {
+ return expectedMAC, err
+ }
+ }
+
+ return expectedMAC, &SignatureError{
+ Signatures: signatures,
+ }
+}
+
// CheckPayloadSignature calculates and verifies SHA1 signature of the given payload
func CheckPayloadSignature(payload []byte, secret string, signature string) (string, error) {
if secret == "" {
return "", errors.New("signature validation secret can not be empty")
}
- signature = strings.TrimPrefix(signature, "sha1=")
+ // Extract the signatures.
+ signatures := ExtractSignatures(signature, "sha1=")
- mac := hmac.New(sha1.New, []byte(secret))
- _, err := mac.Write(payload)
- if err != nil {
- return "", err
- }
- expectedMAC := hex.EncodeToString(mac.Sum(nil))
-
- if !hmac.Equal([]byte(signature), []byte(expectedMAC)) {
- return expectedMAC, &SignatureError{signature}
- }
- return expectedMAC, err
+ // Validate the MAC.
+ return ValidateMAC(payload, hmac.New(sha1.New, []byte(secret)), signatures)
}
// CheckPayloadSignature256 calculates and verifies SHA256 signature of the given payload
@@ -122,19 +195,24 @@ func CheckPayloadSignature256(payload []byte, secret string, signature string) (
return "", errors.New("signature validation secret can not be empty")
}
- signature = strings.TrimPrefix(signature, "sha256=")
+ // Extract the signatures.
+ signatures := ExtractSignatures(signature, "sha256=")
- mac := hmac.New(sha256.New, []byte(secret))
- _, err := mac.Write(payload)
- if err != nil {
- return "", err
- }
- expectedMAC := hex.EncodeToString(mac.Sum(nil))
+ // Validate the MAC.
+ return ValidateMAC(payload, hmac.New(sha256.New, []byte(secret)), signatures)
+}
- if !hmac.Equal([]byte(signature), []byte(expectedMAC)) {
- return expectedMAC, &SignatureError{signature}
+// CheckPayloadSignature512 calculates and verifies SHA512 signature of the given payload
+func CheckPayloadSignature512(payload []byte, secret string, signature string) (string, error) {
+ if secret == "" {
+ return "", errors.New("signature validation secret can not be empty")
}
- return expectedMAC, err
+
+ // Extract the signatures.
+ signatures := ExtractSignatures(signature, "sha512=")
+
+ // Validate the MAC.
+ return ValidateMAC(payload, hmac.New(sha512.New, []byte(secret)), signatures)
}
func CheckScalrSignature(headers map[string]interface{}, body []byte, signingKey string, checkDate bool) (bool, error) {
@@ -157,7 +235,7 @@ func CheckScalrSignature(headers map[string]interface{}, body []byte, signingKey
expectedSignature := hex.EncodeToString(mac.Sum(nil))
if !hmac.Equal([]byte(providedSignature), []byte(expectedSignature)) {
- return false, &SignatureError{providedSignature}
+ return false, &SignatureError{Signature: providedSignature}
}
if !checkDate {
@@ -172,7 +250,7 @@ func CheckScalrSignature(headers map[string]interface{}, body []byte, signingKey
delta := math.Abs(now.Sub(date).Seconds())
if delta > 300 {
- return false, &SignatureError{"outdated"}
+ return false, &SignatureError{Signature: "outdated"}
}
return true, nil
}
@@ -254,9 +332,9 @@ func ReplaceParameter(s string, params interface{}, value interface{}) bool {
}
// GetParameter extracts interface{} value based on the passed string
-func GetParameter(s string, params interface{}) (interface{}, bool) {
+func GetParameter(s string, params interface{}) (interface{}, error) {
if params == nil {
- return nil, false
+ return nil, errors.New("no parameters")
}
paramsValue := reflect.ValueOf(params)
@@ -270,7 +348,7 @@ func GetParameter(s string, params interface{}) (interface{}, bool) {
index, err := strconv.ParseUint(p[0], 10, 64)
if err != nil || paramsValueSliceLength <= int(index) {
- return nil, false
+ return nil, &ParameterNodeError{s}
}
return GetParameter(p[1], params.([]interface{})[index])
@@ -279,18 +357,18 @@ func GetParameter(s string, params interface{}) (interface{}, bool) {
index, err := strconv.ParseUint(s, 10, 64)
if err != nil || paramsValueSliceLength <= int(index) {
- return nil, false
+ return nil, &ParameterNodeError{s}
}
- return params.([]interface{})[index], true
+ return params.([]interface{})[index], nil
}
- return nil, false
+ return nil, &ParameterNodeError{s}
case reflect.Map:
// Check for raw key
if v, ok := params.(map[string]interface{})[s]; ok {
- return v, true
+ return v, nil
}
// Checked for dotted references
@@ -300,19 +378,21 @@ func GetParameter(s string, params interface{}) (interface{}, bool) {
return GetParameter(p[1], pValue)
}
- return pValue, true
+ return pValue, nil
}
}
- return nil, false
+ return nil, &ParameterNodeError{s}
}
// ExtractParameterAsString extracts value from interface{} as string based on the passed string
-func ExtractParameterAsString(s string, params interface{}) (string, bool) {
- if pValue, ok := GetParameter(s, params); ok {
- return fmt.Sprintf("%v", pValue), true
+func ExtractParameterAsString(s string, params interface{}) (string, error) {
+ pValue, err := GetParameter(s, params)
+ if err != nil {
+ return "", err
}
- return "", false
+
+ return fmt.Sprintf("%v", pValue), nil
}
// Argument type specifies the parameter key name and the source it should
@@ -326,7 +406,7 @@ type Argument struct {
// Get Argument method returns the value for the Argument's key name
// based on the Argument's source
-func (ha *Argument) Get(headers, query, payload *map[string]interface{}, context *map[string]interface{}) (string, bool) {
+func (ha *Argument) Get(headers, query, payload *map[string]interface{}, context *map[string]interface{}) (string, error) {
var source *map[string]interface{}
key := ha.Name
@@ -341,35 +421,35 @@ func (ha *Argument) Get(headers, query, payload *map[string]interface{}, context
case SourceContext:
source = context
case SourceString:
- return ha.Name, true
+ return ha.Name, nil
case SourceEntirePayload:
r, err := json.Marshal(payload)
if err != nil {
- return "", false
+ return "", err
}
- return string(r), true
+ return string(r), nil
case SourceEntireHeaders:
r, err := json.Marshal(headers)
if err != nil {
- return "", false
+ return "", err
}
- return string(r), true
+ return string(r), nil
case SourceEntireQuery:
r, err := json.Marshal(query)
if err != nil {
- return "", false
+ return "", err
}
- return string(r), true
+ return string(r), nil
}
if source != nil {
return ExtractParameterAsString(key, *source)
}
- return "", false
+ return "", errors.New("no source for value retrieval")
}
// Header is a structure containing header name and it's value
@@ -455,6 +535,7 @@ type Hook struct {
TriggerRuleMismatchHttpResponseCode int `json:"trigger-rule-mismatch-http-response-code,omitempty"`
IncomingPayloadContentType string `json:"incoming-payload-content-type,omitempty"`
SuccessHttpResponseCode int `json:"success-http-response-code,omitempty"`
+ HTTPMethods []string `json:"http-methods"`
}
// ParseJSONParameters decodes specified arguments to JSON objects and replaces the
@@ -463,7 +544,10 @@ func (h *Hook) ParseJSONParameters(headers, query, payload *map[string]interface
errors := make([]error, 0)
for i := range h.JSONStringParameters {
- if arg, ok := h.JSONStringParameters[i].Get(headers, query, payload, context); ok {
+ arg, err := h.JSONStringParameters[i].Get(headers, query, payload, context)
+ if err != nil {
+ errors = append(errors, &ArgumentError{h.JSONStringParameters[i]})
+ } else {
var newArg map[string]interface{}
decoder := json.NewDecoder(strings.NewReader(string(arg)))
@@ -499,8 +583,6 @@ func (h *Hook) ParseJSONParameters(headers, query, payload *map[string]interface
} else {
errors = append(errors, &SourceError{h.JSONStringParameters[i]})
}
- } else {
- errors = append(errors, &ArgumentError{h.JSONStringParameters[i]})
}
}
@@ -520,12 +602,14 @@ func (h *Hook) ExtractCommandArguments(headers, query, payload *map[string]inter
args = append(args, h.ExecuteCommand)
for i := range h.PassArgumentsToCommand {
- if arg, ok := h.PassArgumentsToCommand[i].Get(headers, query, payload, context); ok {
- args = append(args, arg)
- } else {
+ arg, err := h.PassArgumentsToCommand[i].Get(headers, query, payload, context)
+ if err != nil {
args = append(args, "")
errors = append(errors, &ArgumentError{h.PassArgumentsToCommand[i]})
+ continue
}
+
+ args = append(args, arg)
}
if len(errors) > 0 {
@@ -542,16 +626,18 @@ func (h *Hook) ExtractCommandArgumentsForEnv(headers, query, payload *map[string
args := make([]string, 0)
errors := make([]error, 0)
for i := range h.PassEnvironmentToCommand {
- if arg, ok := h.PassEnvironmentToCommand[i].Get(headers, query, payload, context); ok {
- if h.PassEnvironmentToCommand[i].EnvName != "" {
- // first try to use the EnvName if specified
- args = append(args, h.PassEnvironmentToCommand[i].EnvName+"="+arg)
- } else {
- // then fallback on the name
- args = append(args, EnvNamespace+h.PassEnvironmentToCommand[i].Name+"="+arg)
- }
- } else {
+ arg, err := h.PassEnvironmentToCommand[i].Get(headers, query, payload, context)
+ if err != nil {
errors = append(errors, &ArgumentError{h.PassEnvironmentToCommand[i]})
+ continue
+ }
+
+ if h.PassEnvironmentToCommand[i].EnvName != "" {
+ // first try to use the EnvName if specified
+ args = append(args, h.PassEnvironmentToCommand[i].EnvName+"="+arg)
+ } else {
+ // then fallback on the name
+ args = append(args, EnvNamespace+h.PassEnvironmentToCommand[i].Name+"="+arg)
}
}
@@ -576,30 +662,30 @@ func (h *Hook) ExtractCommandArgumentsForFile(headers, query, payload *map[strin
args := make([]FileParameter, 0)
errors := make([]error, 0)
for i := range h.PassFileToCommand {
- if arg, ok := h.PassFileToCommand[i].Get(headers, query, payload, context); ok {
-
- if h.PassFileToCommand[i].EnvName == "" {
- // if no environment-variable name is set, fall-back on the name
- log.Printf("no ENVVAR name specified, falling back to [%s]", EnvNamespace+strings.ToUpper(h.PassFileToCommand[i].Name))
- h.PassFileToCommand[i].EnvName = EnvNamespace + strings.ToUpper(h.PassFileToCommand[i].Name)
- }
-
- var fileContent []byte
- if h.PassFileToCommand[i].Base64Decode {
- dec, err := base64.StdEncoding.DecodeString(arg)
- if err != nil {
- log.Printf("error decoding string [%s]", err)
- }
- fileContent = []byte(dec)
- } else {
- fileContent = []byte(arg)
- }
-
- args = append(args, FileParameter{EnvName: h.PassFileToCommand[i].EnvName, Data: fileContent})
-
- } else {
+ arg, err := h.PassFileToCommand[i].Get(headers, query, payload, context)
+ if err != nil {
errors = append(errors, &ArgumentError{h.PassFileToCommand[i]})
+ continue
}
+
+ if h.PassFileToCommand[i].EnvName == "" {
+ // if no environment-variable name is set, fall-back on the name
+ log.Printf("no ENVVAR name specified, falling back to [%s]", EnvNamespace+strings.ToUpper(h.PassFileToCommand[i].Name))
+ h.PassFileToCommand[i].EnvName = EnvNamespace + strings.ToUpper(h.PassFileToCommand[i].Name)
+ }
+
+ var fileContent []byte
+ if h.PassFileToCommand[i].Base64Decode {
+ dec, err := base64.StdEncoding.DecodeString(arg)
+ if err != nil {
+ log.Printf("error decoding string [%s]", err)
+ }
+ fileContent = []byte(dec)
+ } else {
+ fileContent = []byte(arg)
+ }
+
+ args = append(args, FileParameter{EnvName: h.PassFileToCommand[i].EnvName, Data: fileContent})
}
if len(errors) > 0 {
@@ -645,8 +731,7 @@ func (h *Hooks) LoadFromFile(path string, asTemplate bool) error {
file = buf.Bytes()
}
- e = yaml.Unmarshal(file, h)
- return e
+ return yaml.Unmarshal(file, h)
}
// Append appends hooks unless the new hooks contain a hook with an ID that already exists
@@ -768,6 +853,7 @@ const (
MatchRegex string = "regex"
MatchHashSHA1 string = "payload-hash-sha1"
MatchHashSHA256 string = "payload-hash-sha256"
+ MatchHashSHA512 string = "payload-hash-sha512"
IPWhitelist string = "ip-whitelist"
ScalrSignature string = "scalr-signature"
)
@@ -782,10 +868,11 @@ func (r MatchRule) Evaluate(headers, query, payload *map[string]interface{}, con
return CheckScalrSignature(*headers, *body, r.Secret, true)
}
- if arg, ok := r.Parameter.Get(headers, query, payload, context); ok {
+ arg, err := r.Parameter.Get(headers, query, payload, context)
+ if err == nil {
switch r.Type {
case MatchValue:
- return arg == r.Value, nil
+ return compare(arg, r.Value), nil
case MatchRegex:
return regexp.MatchString(r.Regex, arg)
case MatchHashSHA1:
@@ -794,9 +881,17 @@ func (r MatchRule) Evaluate(headers, query, payload *map[string]interface{}, con
case MatchHashSHA256:
_, err := CheckPayloadSignature256(*body, r.Secret, arg)
return err == nil, err
+ case MatchHashSHA512:
+ _, err := CheckPayloadSignature512(*body, r.Secret, arg)
+ return err == nil, err
}
}
- return false, nil
+ return false, err
+}
+
+// compare is a helper function for constant time string comparisons.
+func compare(a, b string) bool {
+ return subtle.ConstantTimeCompare([]byte(a), []byte(b)) == 1
}
// getenv provides a template function to retrieve OS environment variables.
diff --git a/hook/hook_test.go b/internal/hook/hook_test.go
similarity index 86%
rename from hook/hook_test.go
rename to internal/hook/hook_test.go
index e8a98bb..489fde2 100644
--- a/hook/hook_test.go
+++ b/internal/hook/hook_test.go
@@ -28,9 +28,9 @@ func TestGetParameter(t *testing.T) {
{"z.b", map[string]interface{}{"a": map[string]interface{}{"z": 2}}, nil, false},
{"a.2", map[string]interface{}{"a": []interface{}{"a", "b"}}, nil, false},
} {
- res, ok := GetParameter(test.key, test.val)
- if ok != test.ok {
- t.Errorf("unexpected result given {%q, %q}: %t\n", test.key, test.val, ok)
+ res, err := GetParameter(test.key, test.val)
+ if (err == nil) != test.ok {
+ t.Errorf("unexpected result given {%q, %q}: %s\n", test.key, test.val, err)
}
if !reflect.DeepEqual(res, test.expect) {
@@ -48,8 +48,11 @@ var checkPayloadSignatureTests = []struct {
}{
{[]byte(`{"a": "z"}`), "secret", "b17e04cbb22afa8ffbff8796fc1894ed27badd9e", "b17e04cbb22afa8ffbff8796fc1894ed27badd9e", true},
{[]byte(`{"a": "z"}`), "secret", "sha1=b17e04cbb22afa8ffbff8796fc1894ed27badd9e", "b17e04cbb22afa8ffbff8796fc1894ed27badd9e", true},
+ {[]byte(`{"a": "z"}`), "secret", "sha1=XXXe04cbb22afa8ffbff8796fc1894ed27badd9e,sha1=b17e04cbb22afa8ffbff8796fc1894ed27badd9e", "b17e04cbb22afa8ffbff8796fc1894ed27badd9e", true},
// failures
{[]byte(`{"a": "z"}`), "secret", "XXXe04cbb22afa8ffbff8796fc1894ed27badd9e", "b17e04cbb22afa8ffbff8796fc1894ed27badd9e", false},
+ {[]byte(`{"a": "z"}`), "secret", "sha1=XXXe04cbb22afa8ffbff8796fc1894ed27badd9e", "b17e04cbb22afa8ffbff8796fc1894ed27badd9e", false},
+ {[]byte(`{"a": "z"}`), "secret", "sha1=XXXe04cbb22afa8ffbff8796fc1894ed27badd9e,sha1=XXXe04cbb22afa8ffbff8796fc1894ed27badd9e", "b17e04cbb22afa8ffbff8796fc1894ed27badd9e", false},
{[]byte(`{"a": "z"}`), "secreX", "b17e04cbb22afa8ffbff8796fc1894ed27badd9e", "900225703e9342328db7307692736e2f7cc7b36e", false},
{[]byte(`{"a": "z"}`), "", "b17e04cbb22afa8ffbff8796fc1894ed27badd9e", "", false},
}
@@ -76,8 +79,11 @@ var checkPayloadSignature256Tests = []struct {
}{
{[]byte(`{"a": "z"}`), "secret", "f417af3a21bd70379b5796d5f013915e7029f62c580fb0f500f59a35a6f04c89", "f417af3a21bd70379b5796d5f013915e7029f62c580fb0f500f59a35a6f04c89", true},
{[]byte(`{"a": "z"}`), "secret", "sha256=f417af3a21bd70379b5796d5f013915e7029f62c580fb0f500f59a35a6f04c89", "f417af3a21bd70379b5796d5f013915e7029f62c580fb0f500f59a35a6f04c89", true},
+ {[]byte(`{"a": "z"}`), "secret", "sha256=XXX7af3a21bd70379b5796d5f013915e7029f62c580fb0f500f59a35a6f04c89,sha256=f417af3a21bd70379b5796d5f013915e7029f62c580fb0f500f59a35a6f04c89", "f417af3a21bd70379b5796d5f013915e7029f62c580fb0f500f59a35a6f04c89", true},
// failures
{[]byte(`{"a": "z"}`), "secret", "XXX7af3a21bd70379b5796d5f013915e7029f62c580fb0f500f59a35a6f04c89", "f417af3a21bd70379b5796d5f013915e7029f62c580fb0f500f59a35a6f04c89", false},
+ {[]byte(`{"a": "z"}`), "secret", "sha256=XXX7af3a21bd70379b5796d5f013915e7029f62c580fb0f500f59a35a6f04c89", "f417af3a21bd70379b5796d5f013915e7029f62c580fb0f500f59a35a6f04c89", false},
+ {[]byte(`{"a": "z"}`), "secret", "sha256=XXX7af3a21bd70379b5796d5f013915e7029f62c580fb0f500f59a35a6f04c89,sha256=XXX7af3a21bd70379b5796d5f013915e7029f62c580fb0f500f59a35a6f04c89", "f417af3a21bd70379b5796d5f013915e7029f62c580fb0f500f59a35a6f04c89", false},
{[]byte(`{"a": "z"}`), "", "XXX7af3a21bd70379b5796d5f013915e7029f62c580fb0f500f59a35a6f04c89", "", false},
}
@@ -94,6 +100,33 @@ func TestCheckPayloadSignature256(t *testing.T) {
}
}
+var checkPayloadSignature512Tests = []struct {
+ payload []byte
+ secret string
+ signature string
+ mac string
+ ok bool
+}{
+ {[]byte(`{"a": "z"}`), "secret", "4ab17cc8ec668ead8bf498f87f8f32848c04d5ca3c9bcfcd3db9363f0deb44e580b329502a7fdff633d4d8fca301cc5c94a55a2fec458c675fb0ff2655898324", "4ab17cc8ec668ead8bf498f87f8f32848c04d5ca3c9bcfcd3db9363f0deb44e580b329502a7fdff633d4d8fca301cc5c94a55a2fec458c675fb0ff2655898324", true},
+ {[]byte(`{"a": "z"}`), "secret", "sha512=4ab17cc8ec668ead8bf498f87f8f32848c04d5ca3c9bcfcd3db9363f0deb44e580b329502a7fdff633d4d8fca301cc5c94a55a2fec458c675fb0ff2655898324", "4ab17cc8ec668ead8bf498f87f8f32848c04d5ca3c9bcfcd3db9363f0deb44e580b329502a7fdff633d4d8fca301cc5c94a55a2fec458c675fb0ff2655898324", true},
+ // failures
+ {[]byte(`{"a": "z"}`), "secret", "74a0081f5b5988f4f3e8b8dd34dadc6291611f2e6260635a7e1535f8e95edb97ff520ba8b152e8ca5760ac42639854f3242e29efc81be73a8bf52d474d31ffea", "4ab17cc8ec668ead8bf498f87f8f32848c04d5ca3c9bcfcd3db9363f0deb44e580b329502a7fdff633d4d8fca301cc5c94a55a2fec458c675fb0ff2655898324", false},
+ {[]byte(`{"a": "z"}`), "", "74a0081f5b5988f4f3e8b8dd34dadc6291611f2e6260635a7e1535f8e95edb97ff520ba8b152e8ca5760ac42639854f3242e29efc81be73a8bf52d474d31ffea", "", false},
+}
+
+func TestCheckPayloadSignature512(t *testing.T) {
+ for _, tt := range checkPayloadSignature512Tests {
+ mac, err := CheckPayloadSignature512(tt.payload, tt.secret, tt.signature)
+ if (err == nil) != tt.ok || mac != tt.mac {
+ t.Errorf("failed to check payload signature {%q, %q, %q}:\nexpected {mac:%#v, ok:%#v},\ngot {mac:%#v, ok:%#v}", tt.payload, tt.secret, tt.signature, tt.mac, tt.ok, mac, (err == nil))
+ }
+
+ if err != nil && tt.mac != "" && strings.Contains(err.Error(), tt.mac) {
+ t.Errorf("error message should not disclose expected mac: %s", err)
+ }
+ }
+}
+
var checkScalrSignatureTests = []struct {
description string
headers map[string]interface{}
@@ -198,9 +231,9 @@ var extractParameterTests = []struct {
func TestExtractParameter(t *testing.T) {
for _, tt := range extractParameterTests {
- value, ok := ExtractParameterAsString(tt.s, tt.params)
- if ok != tt.ok || value != tt.value {
- t.Errorf("failed to extract parameter %q:\nexpected {value:%#v, ok:%#v},\ngot {value:%#v, ok:%#v}", tt.s, tt.value, tt.ok, value, ok)
+ value, err := ExtractParameterAsString(tt.s, tt.params)
+ if (err == nil) != tt.ok || value != tt.value {
+ t.Errorf("failed to extract parameter %q:\nexpected {value:%#v, ok:%#v},\ngot {value:%#v, err:%s}", tt.s, tt.value, tt.ok, value, err)
}
}
}
@@ -225,9 +258,9 @@ var argumentGetTests = []struct {
func TestArgumentGet(t *testing.T) {
for _, tt := range argumentGetTests {
a := Argument{tt.source, tt.name, "", false}
- value, ok := a.Get(tt.headers, tt.query, tt.payload)
- if ok != tt.ok || value != tt.value {
- t.Errorf("failed to get {%q, %q}:\nexpected {value:%#v, ok:%#v},\ngot {value:%#v, ok:%#v}", tt.source, tt.name, tt.value, tt.ok, value, ok)
+ value, err := a.Get(tt.headers, tt.query, tt.payload)
+ if (err == nil) != tt.ok || value != tt.value {
+ t.Errorf("failed to get {%q, %q}:\nexpected {value:%#v, ok:%#v},\ngot {value:%#v, err:%s}", tt.source, tt.name, tt.value, tt.ok, value, err)
}
}
}
@@ -346,10 +379,10 @@ var hooksLoadFromFileTests = []struct {
asTemplate bool
ok bool
}{
- {"../hooks.json.example", false, true},
- {"../hooks.yaml.example", false, true},
- {"../hooks.json.tmpl.example", true, true},
- {"../hooks.yaml.tmpl.example", true, true},
+ {"../../hooks.json.example", false, true},
+ {"../../hooks.yaml.example", false, true},
+ {"../../hooks.json.tmpl.example", true, true},
+ {"../../hooks.yaml.tmpl.example", true, true},
{"", false, true},
// failures
{"missing.json", false, false},
@@ -425,7 +458,7 @@ var matchRuleTests = []struct {
// failures
{"value", "", "", "X", "", Argument{"header", "a", "", false}, &map[string]interface{}{"A": "z"}, nil, nil, []byte{}, "", false, false},
{"regex", "^X", "", "", "", Argument{"header", "a", "", false}, &map[string]interface{}{"A": "z"}, nil, nil, []byte{}, "", false, false},
- {"value", "", "2", "X", "", Argument{"header", "a", "", false}, &map[string]interface{}{"Y": "z"}, nil, nil, []byte{}, "", false, false}, // reference invalid header
+ {"value", "", "2", "X", "", Argument{"header", "a", "", false}, &map[string]interface{}{"Y": "z"}, nil, nil, []byte{}, "", false, true}, // reference invalid header
// errors
{"regex", "*", "", "", "", Argument{"header", "a", "", false}, &map[string]interface{}{"A": "z"}, nil, nil, []byte{}, "", false, true}, // invalid regex
{"payload-hash-sha1", "", "secret", "", "", Argument{"header", "a", "", false}, &map[string]interface{}{"A": ""}, nil, nil, []byte{}, "", false, true}, // invalid hmac
@@ -450,7 +483,7 @@ func TestMatchRule(t *testing.T) {
r := MatchRule{tt.typ, tt.regex, tt.secret, tt.value, tt.param, tt.ipRange}
ok, err := r.Evaluate(tt.headers, tt.query, tt.payload, &tt.body, tt.remoteAddr)
if ok != tt.ok || (err != nil) != tt.err {
- t.Errorf("%d failed to match %#v:\nexpected ok: %#v, err: %v\ngot ok: %#v, err: %v", i, r, tt.ok, tt.err, ok, (err != nil))
+ t.Errorf("%d failed to match %#v:\nexpected ok: %#v, err: %v\ngot ok: %#v, err: %v", i, r, tt.ok, tt.err, ok, err)
}
}
}
@@ -513,7 +546,7 @@ var andRuleTests = []struct {
"invalid rule",
AndRule{{Match: &MatchRule{"value", "", "", "X", Argument{"header", "a", "", false}, ""}}},
&map[string]interface{}{"Y": "z"}, nil, nil, nil,
- false, false,
+ false, true,
},
}
@@ -568,7 +601,7 @@ var orRuleTests = []struct {
{Match: &MatchRule{"value", "", "", "z", Argument{"header", "a", "", false}, ""}},
},
&map[string]interface{}{"Y": "Z"}, nil, nil, []byte{},
- false, false,
+ false, true,
},
}
@@ -601,3 +634,17 @@ func TestNotRule(t *testing.T) {
}
}
}
+
+func TestCompare(t *testing.T) {
+ for _, tt := range []struct {
+ a, b string
+ ok bool
+ }{
+ {"abcd", "abcd", true},
+ {"zyxw", "abcd", false},
+ } {
+ if ok := compare(tt.a, tt.b); ok != tt.ok {
+ t.Errorf("compare failed for %q and %q: got %v\n", tt.a, tt.b, ok)
+ }
+ }
+}
diff --git a/internal/middleware/dumper.go b/internal/middleware/dumper.go
new file mode 100644
index 0000000..582c163
--- /dev/null
+++ b/internal/middleware/dumper.go
@@ -0,0 +1,124 @@
+package middleware
+
+// Derived from from the Goa project, MIT Licensed
+// https://github.com/goadesign/goa/blob/v3/http/middleware/debug.go
+
+import (
+ "bufio"
+ "bytes"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "net"
+ "net/http"
+ "sort"
+ "strings"
+
+ "github.com/gorilla/mux"
+)
+
+// responseDupper tees the response to a buffer and a response writer.
+type responseDupper struct {
+ http.ResponseWriter
+ Buffer *bytes.Buffer
+ Status int
+}
+
+// Dumper returns a debug middleware which prints detailed information about
+// incoming requests and outgoing responses including all headers, parameters
+// and bodies.
+func Dumper(w io.Writer) func(http.Handler) http.Handler {
+ return func(h http.Handler) http.Handler {
+ return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
+ buf := &bytes.Buffer{}
+ // Request ID
+ rid := r.Context().Value(RequestIDKey)
+
+ // Request URL
+ buf.WriteString(fmt.Sprintf("> [%s] %s %s", rid, r.Method, r.URL.String()))
+
+ // Request Headers
+ keys := make([]string, len(r.Header))
+ i := 0
+ for k := range r.Header {
+ keys[i] = k
+ i++
+ }
+ sort.Strings(keys)
+ for _, k := range keys {
+ buf.WriteString(fmt.Sprintf("\n> [%s] %s: %s", rid, k, strings.Join(r.Header[k], ", ")))
+ }
+
+ // Request parameters
+ params := mux.Vars(r)
+ keys = make([]string, len(params))
+ i = 0
+ for k := range params {
+ keys[i] = k
+ i++
+ }
+ sort.Strings(keys)
+ for _, k := range keys {
+ buf.WriteString(fmt.Sprintf("\n> [%s] %s: %s", rid, k, strings.Join(r.Header[k], ", ")))
+ }
+
+ // Request body
+ b, err := ioutil.ReadAll(r.Body)
+ if err != nil {
+ b = []byte("failed to read body: " + err.Error())
+ }
+ if len(b) > 0 {
+ buf.WriteByte('\n')
+ lines := strings.Split(string(b), "\n")
+ for _, line := range lines {
+ buf.WriteString(fmt.Sprintf("> [%s] %s\n", rid, line))
+ }
+ }
+ r.Body = ioutil.NopCloser(bytes.NewBuffer(b))
+
+ dupper := &responseDupper{ResponseWriter: rw, Buffer: &bytes.Buffer{}}
+ h.ServeHTTP(dupper, r)
+
+ buf.WriteString(fmt.Sprintf("\n< [%s] %s", rid, http.StatusText(dupper.Status)))
+ keys = make([]string, len(dupper.Header()))
+ i = 0
+ for k := range dupper.Header() {
+ keys[i] = k
+ i++
+ }
+ sort.Strings(keys)
+ for _, k := range keys {
+ buf.WriteString(fmt.Sprintf("\n< [%s] %s: %s", rid, k, strings.Join(dupper.Header()[k], ", ")))
+ }
+ if dupper.Buffer.Len() > 0 {
+ buf.WriteByte('\n')
+ lines := strings.Split(dupper.Buffer.String(), "\n")
+ for _, line := range lines {
+ buf.WriteString(fmt.Sprintf("< [%s] %s\n", rid, line))
+ }
+ }
+ buf.WriteByte('\n')
+ w.Write(buf.Bytes())
+ })
+ }
+}
+
+// Write writes the data to the buffer and connection as part of an HTTP reply.
+func (r *responseDupper) Write(b []byte) (int, error) {
+ r.Buffer.Write(b)
+ return r.ResponseWriter.Write(b)
+}
+
+// WriteHeader records the status and sends an HTTP response header with status code.
+func (r *responseDupper) WriteHeader(s int) {
+ r.Status = s
+ r.ResponseWriter.WriteHeader(s)
+}
+
+// Hijack supports the http.Hijacker interface.
+func (r *responseDupper) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ if hijacker, ok := r.ResponseWriter.(http.Hijacker); ok {
+ return hijacker.Hijack()
+ }
+ return nil, nil, fmt.Errorf("dumper middleware: inner ResponseWriter cannot be hijacked: %T", r.ResponseWriter)
+}
diff --git a/internal/middleware/logger.go b/internal/middleware/logger.go
new file mode 100644
index 0000000..50c6a44
--- /dev/null
+++ b/internal/middleware/logger.go
@@ -0,0 +1,59 @@
+package middleware
+
+import (
+ "bytes"
+ "fmt"
+ "log"
+ "net/http"
+ "time"
+
+ "github.com/dustin/go-humanize"
+ "github.com/go-chi/chi/middleware"
+)
+
+// Logger is a middleware that logs useful data about each HTTP request.
+type Logger struct {
+ Logger middleware.LoggerInterface
+}
+
+// NewLogger creates a new RequestLogger Handler.
+func NewLogger() func(next http.Handler) http.Handler {
+ return middleware.RequestLogger(&Logger{})
+}
+
+// NewLogEntry creates a new LogEntry for the request.
+func (l *Logger) NewLogEntry(r *http.Request) middleware.LogEntry {
+ e := &LogEntry{
+ req: r,
+ buf: &bytes.Buffer{},
+ }
+
+ return e
+}
+
+// LogEntry represents an individual log entry.
+type LogEntry struct {
+ *Logger
+ req *http.Request
+ buf *bytes.Buffer
+}
+
+// Write constructs and writes the final log entry.
+func (l *LogEntry) Write(status, bytes int, elapsed time.Duration) {
+ rid := GetReqID(l.req.Context())
+ if rid != "" {
+ fmt.Fprintf(l.buf, "[%s] ", rid)
+ }
+
+ fmt.Fprintf(l.buf, "%03d | %s | %s | ", status, humanize.IBytes(uint64(bytes)), elapsed)
+ l.buf.WriteString(l.req.Host + " | " + l.req.Method + " " + l.req.RequestURI)
+ log.Print(l.buf.String())
+}
+
+/// Panic prints the call stack for a panic.
+func (l *LogEntry) Panic(v interface{}, stack []byte) {
+ e := l.NewLogEntry(l.req).(*LogEntry)
+ fmt.Fprintf(e.buf, "panic: %#v", v)
+ log.Print(e.buf.String())
+ log.Print(string(stack))
+}
diff --git a/internal/middleware/request_id.go b/internal/middleware/request_id.go
new file mode 100644
index 0000000..2108af9
--- /dev/null
+++ b/internal/middleware/request_id.go
@@ -0,0 +1,98 @@
+package middleware
+
+// Derived from Goa project, MIT Licensed
+// https://github.com/goadesign/goa/blob/v3/http/middleware/requestid.go
+
+import (
+ "context"
+ "net/http"
+
+ "github.com/gofrs/uuid"
+)
+
+// Key to use when setting the request ID.
+type ctxKeyRequestID int
+
+// RequestIDKey is the key that holds the unique request ID in a request context.
+const RequestIDKey ctxKeyRequestID = 0
+
+// RequestID is a middleware that injects a request ID into the context of each
+// request.
+func RequestID(options ...RequestIDOption) func(http.Handler) http.Handler {
+ o := newRequestIDOptions(options...)
+
+ return func(next http.Handler) http.Handler {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ ctx := r.Context()
+
+ var id string
+
+ if o.UseRequestID() {
+ id = r.Header.Get("X-Request-Id")
+ if o.requestIDLimit > 0 && len(id) > o.requestIDLimit {
+ id = id[:o.requestIDLimit]
+ }
+ }
+
+ if id == "" {
+ id = uuid.Must(uuid.NewV4()).String()[:6]
+ }
+
+ ctx = context.WithValue(ctx, RequestIDKey, id)
+ next.ServeHTTP(w, r.WithContext(ctx))
+ })
+ }
+}
+
+// GetReqID returns a request ID from the given context if one is present.
+// Returns the empty string if a request ID cannot be found.
+func GetReqID(ctx context.Context) string {
+ if ctx == nil {
+ return ""
+ }
+ if reqID, ok := ctx.Value(RequestIDKey).(string); ok {
+ return reqID
+ }
+ return ""
+}
+
+func UseXRequestIDHeaderOption(f bool) RequestIDOption {
+ return func(o *RequestIDOptions) *RequestIDOptions {
+ o.useXRequestID = f
+ return o
+ }
+}
+
+func XRequestIDLimitOption(limit int) RequestIDOption {
+ return func(o *RequestIDOptions) *RequestIDOptions {
+ o.requestIDLimit = limit
+ return o
+ }
+}
+
+type (
+ RequestIDOption func(*RequestIDOptions) *RequestIDOptions
+
+ RequestIDOptions struct {
+ // useXRequestID enabled the use of the X-Request-Id request header as
+ // the request ID.
+ useXRequestID bool
+
+ // requestIDLimit is the maximum length of the X-Request-Id header
+ // allowed. Values longer than this value are truncated. Zero value
+ // means no limit.
+ requestIDLimit int
+ }
+)
+
+func newRequestIDOptions(options ...RequestIDOption) *RequestIDOptions {
+ o := new(RequestIDOptions)
+ for _, opt := range options {
+ o = opt(o)
+ }
+ return o
+}
+
+func (o *RequestIDOptions) UseRequestID() bool {
+ return o.useXRequestID
+}
diff --git a/internal/pidfile/README.md b/internal/pidfile/README.md
new file mode 100644
index 0000000..67f762c
--- /dev/null
+++ b/internal/pidfile/README.md
@@ -0,0 +1,4 @@
+Package pidfile is derived from github.com/moby/moby/pkg/pidfile.
+
+Moby is licensed under the Apache License, Version 2.0.
+Copyright 2012-2017 Docker, Inc.
diff --git a/internal/pidfile/mkdirall.go b/internal/pidfile/mkdirall.go
new file mode 100644
index 0000000..1491366
--- /dev/null
+++ b/internal/pidfile/mkdirall.go
@@ -0,0 +1,11 @@
+// +build !windows
+
+package pidfile
+
+import "os"
+
+// MkdirAll creates a directory named path along with any necessary parents,
+// with permission specified by attribute perm for all dir created.
+func MkdirAll(path string, perm os.FileMode) error {
+ return os.MkdirAll(path, perm)
+}
diff --git a/internal/pidfile/mkdirall_windows.go b/internal/pidfile/mkdirall_windows.go
new file mode 100644
index 0000000..0194de2
--- /dev/null
+++ b/internal/pidfile/mkdirall_windows.go
@@ -0,0 +1,109 @@
+// +build windows
+
+package pidfile
+
+import (
+ "os"
+ "regexp"
+ "syscall"
+ "unsafe"
+
+ "golang.org/x/sys/windows"
+)
+
+// MkdirAll implementation that is volume path aware for Windows. It can be used
+// as a drop-in replacement for os.MkdirAll()
+func MkdirAll(path string, _ os.FileMode) error {
+ return mkdirall(path, false, "")
+}
+
+// mkdirall is a custom version of os.MkdirAll modified for use on Windows
+// so that it is both volume path aware, and can create a directory with
+// a DACL.
+func mkdirall(path string, applyACL bool, sddl string) error {
+ if re := regexp.MustCompile(`^\\\\\?\\Volume{[a-z0-9-]+}$`); re.MatchString(path) {
+ return nil
+ }
+
+ // The rest of this method is largely copied from os.MkdirAll and should be kept
+ // as-is to ensure compatibility.
+
+ // Fast path: if we can tell whether path is a directory or file, stop with success or error.
+ dir, err := os.Stat(path)
+ if err == nil {
+ if dir.IsDir() {
+ return nil
+ }
+ return &os.PathError{
+ Op: "mkdir",
+ Path: path,
+ Err: syscall.ENOTDIR,
+ }
+ }
+
+ // Slow path: make sure parent exists and then call Mkdir for path.
+ i := len(path)
+ for i > 0 && os.IsPathSeparator(path[i-1]) { // Skip trailing path separator.
+ i--
+ }
+
+ j := i
+ for j > 0 && !os.IsPathSeparator(path[j-1]) { // Scan backward over element.
+ j--
+ }
+
+ if j > 1 {
+ // Create parent
+ err = mkdirall(path[0:j-1], false, sddl)
+ if err != nil {
+ return err
+ }
+ }
+
+ // Parent now exists; invoke os.Mkdir or mkdirWithACL and use its result.
+ if applyACL {
+ err = mkdirWithACL(path, sddl)
+ } else {
+ err = os.Mkdir(path, 0)
+ }
+
+ if err != nil {
+ // Handle arguments like "foo/." by
+ // double-checking that directory doesn't exist.
+ dir, err1 := os.Lstat(path)
+ if err1 == nil && dir.IsDir() {
+ return nil
+ }
+ return err
+ }
+ return nil
+}
+
+// mkdirWithACL creates a new directory. If there is an error, it will be of
+// type *PathError. .
+//
+// This is a modified and combined version of os.Mkdir and windows.Mkdir
+// in golang to cater for creating a directory am ACL permitting full
+// access, with inheritance, to any subfolder/file for Built-in Administrators
+// and Local System.
+func mkdirWithACL(name string, sddl string) error {
+ sa := windows.SecurityAttributes{Length: 0}
+ sd, err := windows.SecurityDescriptorFromString(sddl)
+ if err != nil {
+ return &os.PathError{Op: "mkdir", Path: name, Err: err}
+ }
+ sa.Length = uint32(unsafe.Sizeof(sa))
+ sa.InheritHandle = 1
+ sa.SecurityDescriptor = sd
+
+ namep, err := windows.UTF16PtrFromString(name)
+ if err != nil {
+ return &os.PathError{Op: "mkdir", Path: name, Err: err}
+ }
+
+ e := windows.CreateDirectory(namep, &sa)
+ if e != nil {
+ return &os.PathError{Op: "mkdir", Path: name, Err: e}
+ }
+ return nil
+}
diff --git a/internal/pidfile/pidfile.go b/internal/pidfile/pidfile.go
new file mode 100644
index 0000000..c88c159
--- /dev/null
+++ b/internal/pidfile/pidfile.go
@@ -0,0 +1,51 @@
+// Package pidfile provides structure and helper functions to create and remove
+// PID file. A PID file is usually a file used to store the process ID of a
+// running process.
+package pidfile
+
+import (
+ "fmt"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "strconv"
+ "strings"
+)
+
+// PIDFile is a file used to store the process ID of a running process.
+type PIDFile struct {
+ path string
+}
+
+func checkPIDFileAlreadyExists(path string) error {
+ if pidByte, err := ioutil.ReadFile(path); err == nil {
+ pidString := strings.TrimSpace(string(pidByte))
+ if pid, err := strconv.Atoi(pidString); err == nil {
+ if processExists(pid) {
+ return fmt.Errorf("pid file found, ensure webhook is not running or delete %s", path)
+ }
+ }
+ }
+ return nil
+}
+
+// New creates a PIDfile using the specified path.
+func New(path string) (*PIDFile, error) {
+ if err := checkPIDFileAlreadyExists(path); err != nil {
+ return nil, err
+ }
+ // Note MkdirAll returns nil if a directory already exists
+ if err := MkdirAll(filepath.Dir(path), os.FileMode(0755)); err != nil {
+ return nil, err
+ }
+ if err := ioutil.WriteFile(path, []byte(fmt.Sprintf("%d", os.Getpid())), 0644); err != nil {
+ return nil, err
+ }
+
+ return &PIDFile{path: path}, nil
+}
+
+// Remove removes the PIDFile.
+func (file PIDFile) Remove() error {
+ return os.Remove(file.path)
+}
diff --git a/internal/pidfile/pidfile_darwin.go b/internal/pidfile/pidfile_darwin.go
new file mode 100644
index 0000000..2cd001a
--- /dev/null
+++ b/internal/pidfile/pidfile_darwin.go
@@ -0,0 +1,14 @@
+// +build darwin
+
+package pidfile
+
+import (
+ "golang.org/x/sys/unix"
+)
+
+func processExists(pid int) bool {
+ // OS X does not have a proc filesystem.
+ // Use kill -0 pid to judge if the process exists.
+ err := unix.Kill(pid, 0)
+ return err == nil
+}
diff --git a/internal/pidfile/pidfile_test.go b/internal/pidfile/pidfile_test.go
new file mode 100644
index 0000000..73e8af7
--- /dev/null
+++ b/internal/pidfile/pidfile_test.go
@@ -0,0 +1,38 @@
+package pidfile
+
+import (
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "testing"
+)
+
+func TestNewAndRemove(t *testing.T) {
+ dir, err := ioutil.TempDir(os.TempDir(), "test-pidfile")
+ if err != nil {
+ t.Fatal("Could not create test directory")
+ }
+
+ path := filepath.Join(dir, "testfile")
+ file, err := New(path)
+ if err != nil {
+ t.Fatal("Could not create test file", err)
+ }
+
+ _, err = New(path)
+ if err == nil {
+ t.Fatal("Test file creation not blocked")
+ }
+
+ if err := file.Remove(); err != nil {
+ t.Fatal("Could not delete created test file")
+ }
+}
+
+func TestRemoveInvalidPath(t *testing.T) {
+ file := PIDFile{path: filepath.Join("foo", "bar")}
+
+ if err := file.Remove(); err == nil {
+ t.Fatal("Non-existing file doesn't give an error on delete")
+ }
+}
diff --git a/internal/pidfile/pidfile_unix.go b/internal/pidfile/pidfile_unix.go
new file mode 100644
index 0000000..1bf5221
--- /dev/null
+++ b/internal/pidfile/pidfile_unix.go
@@ -0,0 +1,16 @@
+// +build !windows,!darwin
+
+package pidfile
+
+import (
+ "os"
+ "path/filepath"
+ "strconv"
+)
+
+func processExists(pid int) bool {
+ if _, err := os.Stat(filepath.Join("/proc", strconv.Itoa(pid))); err == nil {
+ return true
+ }
+ return false
+}
diff --git a/internal/pidfile/pidfile_windows.go b/internal/pidfile/pidfile_windows.go
new file mode 100644
index 0000000..86850d4
--- /dev/null
+++ b/internal/pidfile/pidfile_windows.go
@@ -0,0 +1,25 @@
+package pidfile
+
+import (
+ "golang.org/x/sys/windows"
+)
+
+const (
+ processQueryLimitedInformation = 0x1000
+
+ stillActive = 259
+)
+
+func processExists(pid int) bool {
+ h, err := windows.OpenProcess(processQueryLimitedInformation, false, uint32(pid))
+ if err != nil {
+ return false
+ }
+ var c uint32
+ err = windows.GetExitCodeProcess(h, &c)
+ windows.Close(h)
+ if err != nil {
+ return c == stillActive
+ }
+ return true
+}
diff --git a/signals.go b/signals.go
index d53a3f6..23f0a74 100644
--- a/signals.go
+++ b/signals.go
@@ -14,6 +14,9 @@ func setupSignals() {
signals = make(chan os.Signal, 1)
signal.Notify(signals, syscall.SIGUSR1)
+ signal.Notify(signals, syscall.SIGHUP)
+ signal.Notify(signals, syscall.SIGTERM)
+ signal.Notify(signals, os.Interrupt)
go watchForSignals()
}
@@ -23,11 +26,26 @@ func watchForSignals() {
for {
sig := <-signals
- if sig == syscall.SIGUSR1 {
+ switch sig {
+ case syscall.SIGUSR1:
log.Println("caught USR1 signal")
-
reloadAllHooks()
- } else {
+
+ case syscall.SIGHUP:
+ log.Println("caught HUP signal")
+ reloadAllHooks()
+
+ case os.Interrupt, syscall.SIGTERM:
+ log.Printf("caught %s signal; exiting\n", sig)
+ if pidFile != nil {
+ err := pidFile.Remove()
+ if err != nil {
+ log.Print(err)
+ }
+ }
+ os.Exit(0)
+
+ default:
log.Printf("caught unhandled signal %+v\n", sig)
}
}
diff --git a/test/hooks.json.tmpl b/test/hooks.json.tmpl
index 2fd90da..0c7fc0c 100644
--- a/test/hooks.json.tmpl
+++ b/test/hooks.json.tmpl
@@ -3,6 +3,7 @@
"id": "github",
"execute-command": "{{ .Hookecho }}",
"command-working-directory": "/",
+ "http-methods": ["Post "],
"include-command-output-in-response": true,
"trigger-rule-mismatch-http-response-code": 400,
"pass-environment-to-command":
@@ -137,6 +138,60 @@
}
}
},
+ {
+ "id": "xml",
+ "execute-command": "{{ .Hookecho }}",
+ "command-working-directory": "/",
+ "response-message": "success",
+ "trigger-rule": {
+ "and": [
+ {
+ "match": {
+ "type": "value",
+ "parameter": {
+ "source": "payload",
+ "name": "app.users.user.0.-name"
+ },
+ "value": "Jeff"
+ }
+ },
+ {
+ "match": {
+ "type": "value",
+ "parameter": {
+ "source": "payload",
+ "name": "app.messages.message.#text"
+ },
+ "value": "Hello!!"
+ }
+ },
+ ],
+ }
+ },
+ {
+ "id": "plex",
+ "execute-command": "{{ .Hookecho }}",
+ "command-working-directory": "/",
+ "response-message": "success",
+ "parse-parameters-as-json": [
+ {
+ "source": "payload",
+ "name": "payload"
+ }
+ ],
+ "trigger-rule":
+ {
+ "match":
+ {
+ "type": "value",
+ "parameter": {
+ "source": "payload",
+ "name": "payload.event"
+ },
+ "value": "media.play"
+ }
+ }
+ },
{
"id": "capture-command-output-on-success-not-by-default",
"pass-arguments-to-command": [
diff --git a/test/hooks.yaml.tmpl b/test/hooks.yaml.tmpl
index c2fffcd..f1e1204 100644
--- a/test/hooks.yaml.tmpl
+++ b/test/hooks.yaml.tmpl
@@ -1,4 +1,6 @@
- id: github
+ http-methods:
+ - "Post "
trigger-rule:
and:
- match:
@@ -76,6 +78,40 @@
include-command-output-in-response: true
command-working-directory: /
+- id: xml
+ execute-command: '{{ .Hookecho }}'
+ command-working-directory: /
+ response-message: success
+ trigger-rule:
+ and:
+ - match:
+ type: value
+ parameter:
+ source: payload
+ name: app.users.user.0.-name
+ value: Jeff
+ - match:
+ type: value
+ parameter:
+ source: payload
+ name: "app.messages.message.#text"
+ value: "Hello!!"
+
+- id: plex
+ trigger-rule:
+ match:
+ type: value
+ parameter:
+ source: payload
+ name: payload.event
+ value: media.play
+ parse-parameters-as-json:
+ - source: payload
+ name: payload
+ execute-command: '{{ .Hookecho }}'
+ response-message: success
+ command-working-directory: /
+
- id: capture-command-output-on-success-not-by-default
pass-arguments-to-command:
- source: string
@@ -113,4 +149,4 @@
- id: warn-on-space
execute-command: '{{ .Hookecho }} foo'
- include-command-output-in-response: true
\ No newline at end of file
+ include-command-output-in-response: true
diff --git a/tls.go b/tls.go
new file mode 100644
index 0000000..8e6cb73
--- /dev/null
+++ b/tls.go
@@ -0,0 +1,85 @@
+package main
+
+import (
+ "crypto/tls"
+ "io"
+ "log"
+ "strings"
+)
+
+func writeTLSSupportedCipherStrings(w io.Writer, min uint16) error {
+ for _, c := range CipherSuites() {
+ var found bool
+
+ for _, v := range c.SupportedVersions {
+ if v >= min {
+ found = true
+ }
+ }
+
+ if !found {
+ continue
+ }
+
+ _, err := w.Write([]byte(c.Name + "\n"))
+ if err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+// getTLSMinVersion converts a version string into a TLS version ID.
+func getTLSMinVersion(v string) uint16 {
+ switch v {
+ case "1.0":
+ return tls.VersionTLS10
+ case "1.1":
+ return tls.VersionTLS11
+ case "1.2", "":
+ return tls.VersionTLS12
+ case "1.3":
+ return tls.VersionTLS13
+ default:
+ log.Fatalln("error: unknown minimum TLS version:", v)
+ return 0
+ }
+}
+
+// getTLSCipherSuites converts a comma separated list of cipher suites into a
+// slice of TLS cipher suite IDs.
+func getTLSCipherSuites(v string) []uint16 {
+ supported := CipherSuites()
+
+ if v == "" {
+ suites := make([]uint16, len(supported))
+
+ for _, cs := range supported {
+ suites = append(suites, cs.ID)
+ }
+
+ return suites
+ }
+
+ var found bool
+ txts := strings.Split(v, ",")
+ suites := make([]uint16, len(txts))
+
+ for _, want := range txts {
+ found = false
+
+ for _, cs := range supported {
+ if want == cs.Name {
+ suites = append(suites, cs.ID)
+ found = true
+ }
+ }
+
+ if !found {
+ log.Fatalln("error: unknown TLS cipher suite:", want)
+ }
+ }
+
+ return suites
+}
diff --git a/vendor/github.com/clbanning/mxj/LICENSE b/vendor/github.com/clbanning/mxj/LICENSE
new file mode 100644
index 0000000..f27bccd
--- /dev/null
+++ b/vendor/github.com/clbanning/mxj/LICENSE
@@ -0,0 +1,55 @@
+Copyright (c) 2012-2016 Charles Banning . All rights reserved.
+
+The MIT License (MIT)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+===============================================================================
+
+Go Language Copyright & License -
+
+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.
+
+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.
diff --git a/vendor/github.com/clbanning/mxj/anyxml.go b/vendor/github.com/clbanning/mxj/anyxml.go
new file mode 100644
index 0000000..ec2f3df
--- /dev/null
+++ b/vendor/github.com/clbanning/mxj/anyxml.go
@@ -0,0 +1,189 @@
+package mxj
+
+import (
+ "encoding/xml"
+ "reflect"
+)
+
+const (
+ DefaultElementTag = "element"
+)
+
+// Encode arbitrary value as XML.
+//
+// Note: unmarshaling the resultant
+// XML may not return the original value, since tag labels may have been injected
+// to create the XML representation of the value.
+/*
+ Encode an arbitrary JSON object.
+ package main
+
+ import (
+ "encoding/json"
+ "fmt"
+ "github.com/clbanning/mxj"
+ )
+
+ func main() {
+ jsondata := []byte(`[
+ { "somekey":"somevalue" },
+ "string",
+ 3.14159265,
+ true
+ ]`)
+ var i interface{}
+ err := json.Unmarshal(jsondata, &i)
+ if err != nil {
+ // do something
+ }
+ x, err := mxj.AnyXmlIndent(i, "", " ", "mydoc")
+ if err != nil {
+ // do something else
+ }
+ fmt.Println(string(x))
+ }
+
+ output:
+
+ somevalue
+ string
+ 3.14159265
+ true
+
+*/
+// Alternative values for DefaultRootTag and DefaultElementTag can be set as:
+// AnyXml( v, myRootTag, myElementTag).
+func AnyXml(v interface{}, tags ...string) ([]byte, error) {
+ var rt, et string
+ if len(tags) == 1 || len(tags) == 2 {
+ rt = tags[0]
+ } else {
+ rt = DefaultRootTag
+ }
+ if len(tags) == 2 {
+ et = tags[1]
+ } else {
+ et = DefaultElementTag
+ }
+
+ if v == nil {
+ if useGoXmlEmptyElemSyntax {
+ return []byte("<" + rt + ">" + rt + ">"), nil
+ }
+ return []byte("<" + rt + "/>"), nil
+ }
+ if reflect.TypeOf(v).Kind() == reflect.Struct {
+ return xml.Marshal(v)
+ }
+
+ var err error
+ s := new(string)
+ p := new(pretty)
+
+ var ss string
+ var b []byte
+ switch v.(type) {
+ case []interface{}:
+ ss = "<" + rt + ">"
+ for _, vv := range v.([]interface{}) {
+ switch vv.(type) {
+ case map[string]interface{}:
+ m := vv.(map[string]interface{})
+ if len(m) == 1 {
+ for tag, val := range m {
+ err = mapToXmlIndent(false, s, tag, val, p)
+ }
+ } else {
+ err = mapToXmlIndent(false, s, et, vv, p)
+ }
+ default:
+ err = mapToXmlIndent(false, s, et, vv, p)
+ }
+ if err != nil {
+ break
+ }
+ }
+ ss += *s + "" + rt + ">"
+ b = []byte(ss)
+ case map[string]interface{}:
+ m := Map(v.(map[string]interface{}))
+ b, err = m.Xml(rt)
+ default:
+ err = mapToXmlIndent(false, s, rt, v, p)
+ b = []byte(*s)
+ }
+
+ return b, err
+}
+
+// Encode an arbitrary value as a pretty XML string.
+// Alternative values for DefaultRootTag and DefaultElementTag can be set as:
+// AnyXmlIndent( v, "", " ", myRootTag, myElementTag).
+func AnyXmlIndent(v interface{}, prefix, indent string, tags ...string) ([]byte, error) {
+ var rt, et string
+ if len(tags) == 1 || len(tags) == 2 {
+ rt = tags[0]
+ } else {
+ rt = DefaultRootTag
+ }
+ if len(tags) == 2 {
+ et = tags[1]
+ } else {
+ et = DefaultElementTag
+ }
+
+ if v == nil {
+ if useGoXmlEmptyElemSyntax {
+ return []byte(prefix + "<" + rt + ">" + rt + ">"), nil
+ }
+ return []byte(prefix + "<" + rt + "/>"), nil
+ }
+ if reflect.TypeOf(v).Kind() == reflect.Struct {
+ return xml.MarshalIndent(v, prefix, indent)
+ }
+
+ var err error
+ s := new(string)
+ p := new(pretty)
+ p.indent = indent
+ p.padding = prefix
+
+ var ss string
+ var b []byte
+ switch v.(type) {
+ case []interface{}:
+ ss = "<" + rt + ">\n"
+ p.Indent()
+ for _, vv := range v.([]interface{}) {
+ switch vv.(type) {
+ case map[string]interface{}:
+ m := vv.(map[string]interface{})
+ if len(m) == 1 {
+ for tag, val := range m {
+ err = mapToXmlIndent(true, s, tag, val, p)
+ }
+ } else {
+ p.start = 1 // we 1 tag in
+ err = mapToXmlIndent(true, s, et, vv, p)
+ *s += "\n"
+ }
+ default:
+ p.start = 0 // in case trailing p.start = 1
+ err = mapToXmlIndent(true, s, et, vv, p)
+ }
+ if err != nil {
+ break
+ }
+ }
+ ss += *s + "" + rt + ">"
+ b = []byte(ss)
+ case map[string]interface{}:
+ m := Map(v.(map[string]interface{}))
+ b, err = m.XmlIndent(prefix, indent, rt)
+ default:
+ err = mapToXmlIndent(true, s, rt, v, p)
+ b = []byte(*s)
+ }
+
+ return b, err
+}
diff --git a/vendor/github.com/clbanning/mxj/atomFeedString.xml b/vendor/github.com/clbanning/mxj/atomFeedString.xml
new file mode 100644
index 0000000..474575a
--- /dev/null
+++ b/vendor/github.com/clbanning/mxj/atomFeedString.xml
@@ -0,0 +1,54 @@
+
+Code Review - My issueshttp://codereview.appspot.com/rietveld<>rietveld: an attempt at pubsubhubbub
+2009-10-04T01:35:58+00:00email-address-removedurn:md5:134d9179c41f806be79b3a5f7877d19a
+ An attempt at adding pubsubhubbub support to Rietveld.
+http://code.google.com/p/pubsubhubbub
+http://code.google.com/p/rietveld/issues/detail?id=155
+
+The server side of the protocol is trivial:
+ 1. add a <link rel="hub" href="hub-server"> tag to all
+ feeds that will be pubsubhubbubbed.
+ 2. every time one of those feeds changes, tell the hub
+ with a simple POST request.
+
+I have tested this by adding debug prints to a local hub
+server and checking that the server got the right publish
+requests.
+
+I can't quite get the server to work, but I think the bug
+is not in my code. I think that the server expects to be
+able to grab the feed and see the feed's actual URL in
+the link rel="self", but the default value for that drops
+the :port from the URL, and I cannot for the life of me
+figure out how to get the Atom generator deep inside
+django not to do that, or even where it is doing that,
+or even what code is running to generate the Atom feed.
+(I thought I knew but I added some assert False statements
+and it kept running!)
+
+Ignoring that particular problem, I would appreciate
+feedback on the right way to get the two values at
+the top of feeds.py marked NOTE(rsc).
+
+
+rietveld: correct tab handling
+2009-10-03T23:02:17+00:00email-address-removedurn:md5:0a2a4f19bb815101f0ba2904aed7c35a
+ This fixes the buggy tab rendering that can be seen at
+http://codereview.appspot.com/116075/diff/1/2
+
+The fundamental problem was that the tab code was
+not being told what column the text began in, so it
+didn't know where to put the tab stops. Another problem
+was that some of the code assumed that string byte
+offsets were the same as column offsets, which is only
+true if there are no tabs.
+
+In the process of fixing this, I cleaned up the arguments
+to Fold and ExpandTabs and renamed them Break and
+_ExpandTabs so that I could be sure that I found all the
+call sites. I also wanted to verify that ExpandTabs was
+not being used from outside intra_region_diff.py.
+
+
+ `
+
diff --git a/vendor/github.com/clbanning/mxj/doc.go b/vendor/github.com/clbanning/mxj/doc.go
new file mode 100644
index 0000000..8ed79a5
--- /dev/null
+++ b/vendor/github.com/clbanning/mxj/doc.go
@@ -0,0 +1,134 @@
+// mxj - A collection of map[string]interface{} and associated XML and JSON utilities.
+// Copyright 2012-2015, 2018 Charles Banning. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file
+
+/*
+Marshal/Unmarshal XML to/from map[string]interface{} values (and JSON); extract/modify values from maps by key or key-path, including wildcards.
+
+mxj supplants the legacy x2j and j2x packages. The subpackage x2j-wrapper is provided to facilitate migrating from the x2j package. The x2j and j2x subpackages provide similar functionality of the old packages but are not function-name compatible with them.
+
+Note: this library was designed for processing ad hoc anonymous messages. Bulk processing large data sets may be much more efficiently performed using the encoding/xml or encoding/json packages from Go's standard library directly.
+
+Related Packages:
+ checkxml: github.com/clbanning/checkxml provides functions for validating XML data.
+
+Notes:
+ 2018.04.18: mv.Xml/mv.XmlIndent encodes non-map[string]interface{} map values - map[string]string, map[int]uint, etc.
+ 2018.03.29: mv.Gob/NewMapGob support gob encoding/decoding of Maps.
+ 2018.03.26: Added mxj/x2j-wrapper sub-package for migrating from legacy x2j package.
+ 2017.02.22: LeafNode paths can use ".N" syntax rather than "[N]" for list member indexing.
+ 2017.02.21: github.com/clbanning/checkxml provides functions for validating XML data.
+ 2017.02.10: SetFieldSeparator changes field separator for args in UpdateValuesForPath, ValuesFor... methods.
+ 2017.02.06: Support XMPP stream processing - HandleXMPPStreamTag().
+ 2016.11.07: Preserve name space prefix syntax in XmlSeq parser - NewMapXmlSeq(), etc.
+ 2016.06.25: Support overriding default XML attribute prefix, "-", in Map keys - SetAttrPrefix().
+ 2016.05.26: Support customization of xml.Decoder by exposing CustomDecoder variable.
+ 2016.03.19: Escape invalid chars when encoding XML attribute and element values - XMLEscapeChars().
+ 2016.03.02: By default decoding XML with float64 and bool value casting will not cast "NaN", "Inf", and "-Inf".
+ To cast them to float64, first set flag with CastNanInf(true).
+ 2016.02.22: New mv.Root(), mv.Elements(), mv.Attributes methods let you examine XML document structure.
+ 2016.02.16: Add CoerceKeysToLower() option to handle tags with mixed capitalization.
+ 2016.02.12: Seek for first xml.StartElement token; only return error if io.EOF is reached first (handles BOM).
+ 2015-12-02: NewMapXmlSeq() with mv.XmlSeq() & co. will try to preserve structure of XML doc when re-encoding.
+ 2014-08-02: AnyXml() and AnyXmlIndent() will try to marshal arbitrary values to XML.
+
+SUMMARY
+
+ type Map map[string]interface{}
+
+ Create a Map value, 'mv', from any map[string]interface{} value, 'v':
+ mv := Map(v)
+
+ Unmarshal / marshal XML as a Map value, 'mv':
+ mv, err := NewMapXml(xmlValue) // unmarshal
+ xmlValue, err := mv.Xml() // marshal
+
+ Unmarshal XML from an io.Reader as a Map value, 'mv':
+ mv, err := NewMapXmlReader(xmlReader) // repeated calls, as with an os.File Reader, will process stream
+ mv, raw, err := NewMapXmlReaderRaw(xmlReader) // 'raw' is the raw XML that was decoded
+
+ Marshal Map value, 'mv', to an XML Writer (io.Writer):
+ err := mv.XmlWriter(xmlWriter)
+ raw, err := mv.XmlWriterRaw(xmlWriter) // 'raw' is the raw XML that was written on xmlWriter
+
+ Also, for prettified output:
+ xmlValue, err := mv.XmlIndent(prefix, indent, ...)
+ err := mv.XmlIndentWriter(xmlWriter, prefix, indent, ...)
+ raw, err := mv.XmlIndentWriterRaw(xmlWriter, prefix, indent, ...)
+
+ Bulk process XML with error handling (note: handlers must return a boolean value):
+ err := HandleXmlReader(xmlReader, mapHandler(Map), errHandler(error))
+ err := HandleXmlReaderRaw(xmlReader, mapHandler(Map, []byte), errHandler(error, []byte))
+
+ Converting XML to JSON: see Examples for NewMapXml and HandleXmlReader.
+
+ There are comparable functions and methods for JSON processing.
+
+ Arbitrary structure values can be decoded to / encoded from Map values:
+ mv, err := NewMapStruct(structVal)
+ err := mv.Struct(structPointer)
+
+ To work with XML tag values, JSON or Map key values or structure field values, decode the XML, JSON
+ or structure to a Map value, 'mv', or cast a map[string]interface{} value to a Map value, 'mv', then:
+ paths := mv.PathsForKey(key)
+ path := mv.PathForKeyShortest(key)
+ values, err := mv.ValuesForKey(key, subkeys)
+ values, err := mv.ValuesForPath(path, subkeys) // 'path' can be dot-notation with wildcards and indexed arrays.
+ count, err := mv.UpdateValuesForPath(newVal, path, subkeys)
+
+ Get everything at once, irrespective of path depth:
+ leafnodes := mv.LeafNodes()
+ leafvalues := mv.LeafValues()
+
+ A new Map with whatever keys are desired can be created from the current Map and then encoded in XML
+ or JSON. (Note: keys can use dot-notation. 'oldKey' can also use wildcards and indexed arrays.)
+ newMap, err := mv.NewMap("oldKey_1:newKey_1", "oldKey_2:newKey_2", ..., "oldKey_N:newKey_N")
+ newMap, err := mv.NewMap("oldKey1", "oldKey3", "oldKey5") // a subset of 'mv'; see "examples/partial.go"
+ newXml, err := newMap.Xml() // for example
+ newJson, err := newMap.Json() // ditto
+
+XML PARSING CONVENTIONS
+
+ Using NewMapXml()
+
+ - Attributes are parsed to `map[string]interface{}` values by prefixing a hyphen, `-`,
+ to the attribute label. (Unless overridden by `PrependAttrWithHyphen(false)` or
+ `SetAttrPrefix()`.)
+ - If the element is a simple element and has attributes, the element value
+ is given the key `#text` for its `map[string]interface{}` representation. (See
+ the 'atomFeedString.xml' test data, below.)
+ - XML comments, directives, and process instructions are ignored.
+ - If CoerceKeysToLower() has been called, then the resultant keys will be lower case.
+
+ Using NewMapXmlSeq()
+
+ - Attributes are parsed to `map["#attr"]map[]map[string]interface{}`values
+ where the `` value has "#text" and "#seq" keys - the "#text" key holds the
+ value for ``.
+ - All elements, except for the root, have a "#seq" key.
+ - Comments, directives, and process instructions are unmarshalled into the Map using the
+ keys "#comment", "#directive", and "#procinst", respectively. (See documentation for more
+ specifics.)
+ - Name space syntax is preserved:
+ - something parses to map["ns:key"]interface{}{"something"}
+ - xmlns:ns="http://myns.com/ns" parses to map["xmlns:ns"]interface{}{"http://myns.com/ns"}
+
+ Both
+
+ - By default, "Nan", "Inf", and "-Inf" values are not cast to float64. If you want them
+ to be cast, set a flag to cast them using CastNanInf(true).
+
+XML ENCODING CONVENTIONS
+
+ - 'nil' Map values, which may represent 'null' JSON values, are encoded as "".
+ NOTE: the operation is not symmetric as "" elements are decoded as 'tag:""' Map values,
+ which, then, encode in JSON as '"tag":""' values..
+ - ALSO: there is no guarantee that the encoded XML doc will be the same as the decoded one. (Go
+ randomizes the walk through map[string]interface{} values.) If you plan to re-encode the
+ Map value to XML and want the same sequencing of elements look at NewMapXmlSeq() and
+ mv.XmlSeq() - these try to preserve the element sequencing but with added complexity when
+ working with the Map representation.
+
+*/
+package mxj
diff --git a/vendor/github.com/clbanning/mxj/escapechars.go b/vendor/github.com/clbanning/mxj/escapechars.go
new file mode 100644
index 0000000..bee0442
--- /dev/null
+++ b/vendor/github.com/clbanning/mxj/escapechars.go
@@ -0,0 +1,54 @@
+// Copyright 2016 Charles Banning. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file
+
+package mxj
+
+import (
+ "bytes"
+)
+
+var xmlEscapeChars bool
+
+// XMLEscapeChars(true) forces escaping invalid characters in attribute and element values.
+// NOTE: this is brute force with NO interrogation of '&' being escaped already; if it is
+// then '&' will be re-escaped as '&'.
+//
+/*
+ The values are:
+ " "
+ ' '
+ < <
+ > >
+ & &
+*/
+func XMLEscapeChars(b bool) {
+ xmlEscapeChars = b
+}
+
+// Scan for '&' first, since 's' may contain "&" that is parsed to "&"
+// - or "<" that is parsed to "<".
+var escapechars = [][2][]byte{
+ {[]byte(`&`), []byte(`&`)},
+ {[]byte(`<`), []byte(`<`)},
+ {[]byte(`>`), []byte(`>`)},
+ {[]byte(`"`), []byte(`"`)},
+ {[]byte(`'`), []byte(`'`)},
+}
+
+func escapeChars(s string) string {
+ if len(s) == 0 {
+ return s
+ }
+
+ b := []byte(s)
+ for _, v := range escapechars {
+ n := bytes.Count(b, v[0])
+ if n == 0 {
+ continue
+ }
+ b = bytes.Replace(b, v[0], v[1], n)
+ }
+ return string(b)
+}
+
diff --git a/vendor/github.com/clbanning/mxj/exists.go b/vendor/github.com/clbanning/mxj/exists.go
new file mode 100644
index 0000000..2fb3084
--- /dev/null
+++ b/vendor/github.com/clbanning/mxj/exists.go
@@ -0,0 +1,7 @@
+package mxj
+
+// Checks whether the path exists
+func (mv Map) Exists(path string, subkeys ...string) bool {
+ v, err := mv.ValuesForPath(path, subkeys...)
+ return err == nil && len(v) > 0
+}
diff --git a/vendor/github.com/clbanning/mxj/files.go b/vendor/github.com/clbanning/mxj/files.go
new file mode 100644
index 0000000..27e06e1
--- /dev/null
+++ b/vendor/github.com/clbanning/mxj/files.go
@@ -0,0 +1,287 @@
+package mxj
+
+import (
+ "fmt"
+ "io"
+ "os"
+)
+
+type Maps []Map
+
+func NewMaps() Maps {
+ return make(Maps, 0)
+}
+
+type MapRaw struct {
+ M Map
+ R []byte
+}
+
+// NewMapsFromXmlFile - creates an array from a file of JSON values.
+func NewMapsFromJsonFile(name string) (Maps, error) {
+ fi, err := os.Stat(name)
+ if err != nil {
+ return nil, err
+ }
+ if !fi.Mode().IsRegular() {
+ return nil, fmt.Errorf("file %s is not a regular file", name)
+ }
+
+ fh, err := os.Open(name)
+ if err != nil {
+ return nil, err
+ }
+ defer fh.Close()
+
+ am := make([]Map, 0)
+ for {
+ m, raw, err := NewMapJsonReaderRaw(fh)
+ if err != nil && err != io.EOF {
+ return am, fmt.Errorf("error: %s - reading: %s", err.Error(), string(raw))
+ }
+ if len(m) > 0 {
+ am = append(am, m)
+ }
+ if err == io.EOF {
+ break
+ }
+ }
+ return am, nil
+}
+
+// ReadMapsFromJsonFileRaw - creates an array of MapRaw from a file of JSON values.
+func NewMapsFromJsonFileRaw(name string) ([]MapRaw, error) {
+ fi, err := os.Stat(name)
+ if err != nil {
+ return nil, err
+ }
+ if !fi.Mode().IsRegular() {
+ return nil, fmt.Errorf("file %s is not a regular file", name)
+ }
+
+ fh, err := os.Open(name)
+ if err != nil {
+ return nil, err
+ }
+ defer fh.Close()
+
+ am := make([]MapRaw, 0)
+ for {
+ mr := new(MapRaw)
+ mr.M, mr.R, err = NewMapJsonReaderRaw(fh)
+ if err != nil && err != io.EOF {
+ return am, fmt.Errorf("error: %s - reading: %s", err.Error(), string(mr.R))
+ }
+ if len(mr.M) > 0 {
+ am = append(am, *mr)
+ }
+ if err == io.EOF {
+ break
+ }
+ }
+ return am, nil
+}
+
+// NewMapsFromXmlFile - creates an array from a file of XML values.
+func NewMapsFromXmlFile(name string) (Maps, error) {
+ fi, err := os.Stat(name)
+ if err != nil {
+ return nil, err
+ }
+ if !fi.Mode().IsRegular() {
+ return nil, fmt.Errorf("file %s is not a regular file", name)
+ }
+
+ fh, err := os.Open(name)
+ if err != nil {
+ return nil, err
+ }
+ defer fh.Close()
+
+ am := make([]Map, 0)
+ for {
+ m, raw, err := NewMapXmlReaderRaw(fh)
+ if err != nil && err != io.EOF {
+ return am, fmt.Errorf("error: %s - reading: %s", err.Error(), string(raw))
+ }
+ if len(m) > 0 {
+ am = append(am, m)
+ }
+ if err == io.EOF {
+ break
+ }
+ }
+ return am, nil
+}
+
+// NewMapsFromXmlFileRaw - creates an array of MapRaw from a file of XML values.
+// NOTE: the slice with the raw XML is clean with no extra capacity - unlike NewMapXmlReaderRaw().
+// It is slow at parsing a file from disk and is intended for relatively small utility files.
+func NewMapsFromXmlFileRaw(name string) ([]MapRaw, error) {
+ fi, err := os.Stat(name)
+ if err != nil {
+ return nil, err
+ }
+ if !fi.Mode().IsRegular() {
+ return nil, fmt.Errorf("file %s is not a regular file", name)
+ }
+
+ fh, err := os.Open(name)
+ if err != nil {
+ return nil, err
+ }
+ defer fh.Close()
+
+ am := make([]MapRaw, 0)
+ for {
+ mr := new(MapRaw)
+ mr.M, mr.R, err = NewMapXmlReaderRaw(fh)
+ if err != nil && err != io.EOF {
+ return am, fmt.Errorf("error: %s - reading: %s", err.Error(), string(mr.R))
+ }
+ if len(mr.M) > 0 {
+ am = append(am, *mr)
+ }
+ if err == io.EOF {
+ break
+ }
+ }
+ return am, nil
+}
+
+// ------------------------ Maps writing -------------------------
+// These are handy-dandy methods for dumping configuration data, etc.
+
+// JsonString - analogous to mv.Json()
+func (mvs Maps) JsonString(safeEncoding ...bool) (string, error) {
+ var s string
+ for _, v := range mvs {
+ j, err := v.Json()
+ if err != nil {
+ return s, err
+ }
+ s += string(j)
+ }
+ return s, nil
+}
+
+// JsonStringIndent - analogous to mv.JsonIndent()
+func (mvs Maps) JsonStringIndent(prefix, indent string, safeEncoding ...bool) (string, error) {
+ var s string
+ var haveFirst bool
+ for _, v := range mvs {
+ j, err := v.JsonIndent(prefix, indent)
+ if err != nil {
+ return s, err
+ }
+ if haveFirst {
+ s += "\n"
+ } else {
+ haveFirst = true
+ }
+ s += string(j)
+ }
+ return s, nil
+}
+
+// XmlString - analogous to mv.Xml()
+func (mvs Maps) XmlString() (string, error) {
+ var s string
+ for _, v := range mvs {
+ x, err := v.Xml()
+ if err != nil {
+ return s, err
+ }
+ s += string(x)
+ }
+ return s, nil
+}
+
+// XmlStringIndent - analogous to mv.XmlIndent()
+func (mvs Maps) XmlStringIndent(prefix, indent string) (string, error) {
+ var s string
+ for _, v := range mvs {
+ x, err := v.XmlIndent(prefix, indent)
+ if err != nil {
+ return s, err
+ }
+ s += string(x)
+ }
+ return s, nil
+}
+
+// JsonFile - write Maps to named file as JSON
+// Note: the file will be created, if necessary; if it exists it will be truncated.
+// If you need to append to a file, open it and use JsonWriter method.
+func (mvs Maps) JsonFile(file string, safeEncoding ...bool) error {
+ var encoding bool
+ if len(safeEncoding) == 1 {
+ encoding = safeEncoding[0]
+ }
+ s, err := mvs.JsonString(encoding)
+ if err != nil {
+ return err
+ }
+ fh, err := os.Create(file)
+ if err != nil {
+ return err
+ }
+ defer fh.Close()
+ fh.WriteString(s)
+ return nil
+}
+
+// JsonFileIndent - write Maps to named file as pretty JSON
+// Note: the file will be created, if necessary; if it exists it will be truncated.
+// If you need to append to a file, open it and use JsonIndentWriter method.
+func (mvs Maps) JsonFileIndent(file, prefix, indent string, safeEncoding ...bool) error {
+ var encoding bool
+ if len(safeEncoding) == 1 {
+ encoding = safeEncoding[0]
+ }
+ s, err := mvs.JsonStringIndent(prefix, indent, encoding)
+ if err != nil {
+ return err
+ }
+ fh, err := os.Create(file)
+ if err != nil {
+ return err
+ }
+ defer fh.Close()
+ fh.WriteString(s)
+ return nil
+}
+
+// XmlFile - write Maps to named file as XML
+// Note: the file will be created, if necessary; if it exists it will be truncated.
+// If you need to append to a file, open it and use XmlWriter method.
+func (mvs Maps) XmlFile(file string) error {
+ s, err := mvs.XmlString()
+ if err != nil {
+ return err
+ }
+ fh, err := os.Create(file)
+ if err != nil {
+ return err
+ }
+ defer fh.Close()
+ fh.WriteString(s)
+ return nil
+}
+
+// XmlFileIndent - write Maps to named file as pretty XML
+// Note: the file will be created,if necessary; if it exists it will be truncated.
+// If you need to append to a file, open it and use XmlIndentWriter method.
+func (mvs Maps) XmlFileIndent(file, prefix, indent string) error {
+ s, err := mvs.XmlStringIndent(prefix, indent)
+ if err != nil {
+ return err
+ }
+ fh, err := os.Create(file)
+ if err != nil {
+ return err
+ }
+ defer fh.Close()
+ fh.WriteString(s)
+ return nil
+}
diff --git a/vendor/github.com/clbanning/mxj/files_test.badjson b/vendor/github.com/clbanning/mxj/files_test.badjson
new file mode 100644
index 0000000..d187200
--- /dev/null
+++ b/vendor/github.com/clbanning/mxj/files_test.badjson
@@ -0,0 +1,2 @@
+{ "this":"is", "a":"test", "file":"for", "files_test.go":"case" }
+{ "with":"some", "bad":JSON, "in":"it" }
diff --git a/vendor/github.com/clbanning/mxj/files_test.badxml b/vendor/github.com/clbanning/mxj/files_test.badxml
new file mode 100644
index 0000000..4736ef9
--- /dev/null
+++ b/vendor/github.com/clbanning/mxj/files_test.badxml
@@ -0,0 +1,9 @@
+
+ test
+ for files.go
+
+
+ some
+ doc
+ test case
+
diff --git a/vendor/github.com/clbanning/mxj/files_test.json b/vendor/github.com/clbanning/mxj/files_test.json
new file mode 100644
index 0000000..e9a3ddf
--- /dev/null
+++ b/vendor/github.com/clbanning/mxj/files_test.json
@@ -0,0 +1,2 @@
+{ "this":"is", "a":"test", "file":"for", "files_test.go":"case" }
+{ "with":"just", "two":2, "JSON":"values", "true":true }
diff --git a/vendor/github.com/clbanning/mxj/files_test.xml b/vendor/github.com/clbanning/mxj/files_test.xml
new file mode 100644
index 0000000..65cf021
--- /dev/null
+++ b/vendor/github.com/clbanning/mxj/files_test.xml
@@ -0,0 +1,9 @@
+
+ test
+ for files.go
+
+
+ some
+ doc
+ test case
+
diff --git a/vendor/github.com/clbanning/mxj/files_test_dup.json b/vendor/github.com/clbanning/mxj/files_test_dup.json
new file mode 100644
index 0000000..2becb6a
--- /dev/null
+++ b/vendor/github.com/clbanning/mxj/files_test_dup.json
@@ -0,0 +1 @@
+{"a":"test","file":"for","files_test.go":"case","this":"is"}{"JSON":"values","true":true,"two":2,"with":"just"}
\ No newline at end of file
diff --git a/vendor/github.com/clbanning/mxj/files_test_dup.xml b/vendor/github.com/clbanning/mxj/files_test_dup.xml
new file mode 100644
index 0000000..f68d22e
--- /dev/null
+++ b/vendor/github.com/clbanning/mxj/files_test_dup.xml
@@ -0,0 +1 @@
+for files.gotestdoctest casesome
\ No newline at end of file
diff --git a/vendor/github.com/clbanning/mxj/files_test_indent.json b/vendor/github.com/clbanning/mxj/files_test_indent.json
new file mode 100644
index 0000000..6fde156
--- /dev/null
+++ b/vendor/github.com/clbanning/mxj/files_test_indent.json
@@ -0,0 +1,12 @@
+{
+ "a": "test",
+ "file": "for",
+ "files_test.go": "case",
+ "this": "is"
+}
+{
+ "JSON": "values",
+ "true": true,
+ "two": 2,
+ "with": "just"
+}
\ No newline at end of file
diff --git a/vendor/github.com/clbanning/mxj/files_test_indent.xml b/vendor/github.com/clbanning/mxj/files_test_indent.xml
new file mode 100644
index 0000000..8c91a1d
--- /dev/null
+++ b/vendor/github.com/clbanning/mxj/files_test_indent.xml
@@ -0,0 +1,8 @@
+
+ for files.go
+ test
+
+ doc
+ test case
+ some
+
\ No newline at end of file
diff --git a/vendor/github.com/clbanning/mxj/gob.go b/vendor/github.com/clbanning/mxj/gob.go
new file mode 100644
index 0000000..d56c2fd
--- /dev/null
+++ b/vendor/github.com/clbanning/mxj/gob.go
@@ -0,0 +1,35 @@
+// gob.go - Encode/Decode a Map into a gob object.
+
+package mxj
+
+import (
+ "bytes"
+ "encoding/gob"
+)
+
+// NewMapGob returns a Map value for a gob object that has been
+// encoded from a map[string]interface{} (or compatible type) value.
+// It is intended to provide symmetric handling of Maps that have
+// been encoded using mv.Gob.
+func NewMapGob(gobj []byte) (Map, error) {
+ m := make(map[string]interface{}, 0)
+ if len(gobj) == 0 {
+ return m, nil
+ }
+ r := bytes.NewReader(gobj)
+ dec := gob.NewDecoder(r)
+ if err := dec.Decode(&m); err != nil {
+ return m, err
+ }
+ return m, nil
+}
+
+// Gob returns a gob-encoded value for the Map 'mv'.
+func (mv Map) Gob() ([]byte, error) {
+ var buf bytes.Buffer
+ enc := gob.NewEncoder(&buf)
+ if err := enc.Encode(map[string]interface{}(mv)); err != nil {
+ return nil, err
+ }
+ return buf.Bytes(), nil
+}
diff --git a/vendor/github.com/clbanning/mxj/json.go b/vendor/github.com/clbanning/mxj/json.go
new file mode 100644
index 0000000..eb2c05a
--- /dev/null
+++ b/vendor/github.com/clbanning/mxj/json.go
@@ -0,0 +1,323 @@
+// Copyright 2012-2014 Charles Banning. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file
+
+package mxj
+
+import (
+ "bytes"
+ "encoding/json"
+ "fmt"
+ "io"
+ "time"
+)
+
+// ------------------------------ write JSON -----------------------
+
+// Just a wrapper on json.Marshal.
+// If option safeEncoding is'true' then safe encoding of '<', '>' and '&'
+// is preserved. (see encoding/json#Marshal, encoding/json#Encode)
+func (mv Map) Json(safeEncoding ...bool) ([]byte, error) {
+ var s bool
+ if len(safeEncoding) == 1 {
+ s = safeEncoding[0]
+ }
+
+ b, err := json.Marshal(mv)
+
+ if !s {
+ b = bytes.Replace(b, []byte("\\u003c"), []byte("<"), -1)
+ b = bytes.Replace(b, []byte("\\u003e"), []byte(">"), -1)
+ b = bytes.Replace(b, []byte("\\u0026"), []byte("&"), -1)
+ }
+ return b, err
+}
+
+// Just a wrapper on json.MarshalIndent.
+// If option safeEncoding is'true' then safe encoding of '<' , '>' and '&'
+// is preserved. (see encoding/json#Marshal, encoding/json#Encode)
+func (mv Map) JsonIndent(prefix, indent string, safeEncoding ...bool) ([]byte, error) {
+ var s bool
+ if len(safeEncoding) == 1 {
+ s = safeEncoding[0]
+ }
+
+ b, err := json.MarshalIndent(mv, prefix, indent)
+ if !s {
+ b = bytes.Replace(b, []byte("\\u003c"), []byte("<"), -1)
+ b = bytes.Replace(b, []byte("\\u003e"), []byte(">"), -1)
+ b = bytes.Replace(b, []byte("\\u0026"), []byte("&"), -1)
+ }
+ return b, err
+}
+
+// The following implementation is provided for symmetry with NewMapJsonReader[Raw]
+// The names will also provide a key for the number of return arguments.
+
+// Writes the Map as JSON on the Writer.
+// If 'safeEncoding' is 'true', then "safe" encoding of '<', '>' and '&' is preserved.
+func (mv Map) JsonWriter(jsonWriter io.Writer, safeEncoding ...bool) error {
+ b, err := mv.Json(safeEncoding...)
+ if err != nil {
+ return err
+ }
+
+ _, err = jsonWriter.Write(b)
+ return err
+}
+
+// Writes the Map as JSON on the Writer. []byte is the raw JSON that was written.
+// If 'safeEncoding' is 'true', then "safe" encoding of '<', '>' and '&' is preserved.
+func (mv Map) JsonWriterRaw(jsonWriter io.Writer, safeEncoding ...bool) ([]byte, error) {
+ b, err := mv.Json(safeEncoding...)
+ if err != nil {
+ return b, err
+ }
+
+ _, err = jsonWriter.Write(b)
+ return b, err
+}
+
+// Writes the Map as pretty JSON on the Writer.
+// If 'safeEncoding' is 'true', then "safe" encoding of '<', '>' and '&' is preserved.
+func (mv Map) JsonIndentWriter(jsonWriter io.Writer, prefix, indent string, safeEncoding ...bool) error {
+ b, err := mv.JsonIndent(prefix, indent, safeEncoding...)
+ if err != nil {
+ return err
+ }
+
+ _, err = jsonWriter.Write(b)
+ return err
+}
+
+// Writes the Map as pretty JSON on the Writer. []byte is the raw JSON that was written.
+// If 'safeEncoding' is 'true', then "safe" encoding of '<', '>' and '&' is preserved.
+func (mv Map) JsonIndentWriterRaw(jsonWriter io.Writer, prefix, indent string, safeEncoding ...bool) ([]byte, error) {
+ b, err := mv.JsonIndent(prefix, indent, safeEncoding...)
+ if err != nil {
+ return b, err
+ }
+
+ _, err = jsonWriter.Write(b)
+ return b, err
+}
+
+// --------------------------- read JSON -----------------------------
+
+// Decode numericvalues as json.Number type Map values - see encoding/json#Number.
+// NOTE: this is for decoding JSON into a Map with NewMapJson(), NewMapJsonReader(),
+// etc.; it does not affect NewMapXml(), etc. The XML encoders mv.Xml() and mv.XmlIndent()
+// do recognize json.Number types; a JSON object can be decoded to a Map with json.Number
+// value types and the resulting Map can be correctly encoded into a XML object.
+var JsonUseNumber bool
+
+// Just a wrapper on json.Unmarshal
+// Converting JSON to XML is a simple as:
+// ...
+// mapVal, merr := mxj.NewMapJson(jsonVal)
+// if merr != nil {
+// // handle error
+// }
+// xmlVal, xerr := mapVal.Xml()
+// if xerr != nil {
+// // handle error
+// }
+// NOTE: as a special case, passing a list, e.g., [{"some-null-value":"", "a-non-null-value":"bar"}],
+// will be interpreted as having the root key 'object' prepended - {"object":[ ... ]} - to unmarshal to a Map.
+// See mxj/j2x/j2x_test.go.
+func NewMapJson(jsonVal []byte) (Map, error) {
+ // empty or nil begets empty
+ if len(jsonVal) == 0 {
+ m := make(map[string]interface{}, 0)
+ return m, nil
+ }
+ // handle a goofy case ...
+ if jsonVal[0] == '[' {
+ jsonVal = []byte(`{"object":` + string(jsonVal) + `}`)
+ }
+ m := make(map[string]interface{})
+ // err := json.Unmarshal(jsonVal, &m)
+ buf := bytes.NewReader(jsonVal)
+ dec := json.NewDecoder(buf)
+ if JsonUseNumber {
+ dec.UseNumber()
+ }
+ err := dec.Decode(&m)
+ return m, err
+}
+
+// Retrieve a Map value from an io.Reader.
+// NOTE: The raw JSON off the reader is buffered to []byte using a ByteReader. If the io.Reader is an
+// os.File, there may be significant performance impact. If the io.Reader is wrapping a []byte
+// value in-memory, however, such as http.Request.Body you CAN use it to efficiently unmarshal
+// a JSON object.
+func NewMapJsonReader(jsonReader io.Reader) (Map, error) {
+ jb, err := getJson(jsonReader)
+ if err != nil || len(*jb) == 0 {
+ return nil, err
+ }
+
+ // Unmarshal the 'presumed' JSON string
+ return NewMapJson(*jb)
+}
+
+// Retrieve a Map value and raw JSON - []byte - from an io.Reader.
+// NOTE: The raw JSON off the reader is buffered to []byte using a ByteReader. If the io.Reader is an
+// os.File, there may be significant performance impact. If the io.Reader is wrapping a []byte
+// value in-memory, however, such as http.Request.Body you CAN use it to efficiently unmarshal
+// a JSON object and retrieve the raw JSON in a single call.
+func NewMapJsonReaderRaw(jsonReader io.Reader) (Map, []byte, error) {
+ jb, err := getJson(jsonReader)
+ if err != nil || len(*jb) == 0 {
+ return nil, *jb, err
+ }
+
+ // Unmarshal the 'presumed' JSON string
+ m, merr := NewMapJson(*jb)
+ return m, *jb, merr
+}
+
+// Pull the next JSON string off the stream: just read from first '{' to its closing '}'.
+// Returning a pointer to the slice saves 16 bytes - maybe unnecessary, but internal to package.
+func getJson(rdr io.Reader) (*[]byte, error) {
+ bval := make([]byte, 1)
+ jb := make([]byte, 0)
+ var inQuote, inJson bool
+ var parenCnt int
+ var previous byte
+
+ // scan the input for a matched set of {...}
+ // json.Unmarshal will handle syntax checking.
+ for {
+ _, err := rdr.Read(bval)
+ if err != nil {
+ if err == io.EOF && inJson && parenCnt > 0 {
+ return &jb, fmt.Errorf("no closing } for JSON string: %s", string(jb))
+ }
+ return &jb, err
+ }
+ switch bval[0] {
+ case '{':
+ if !inQuote {
+ parenCnt++
+ inJson = true
+ }
+ case '}':
+ if !inQuote {
+ parenCnt--
+ }
+ if parenCnt < 0 {
+ return nil, fmt.Errorf("closing } without opening {: %s", string(jb))
+ }
+ case '"':
+ if inQuote {
+ if previous == '\\' {
+ break
+ }
+ inQuote = false
+ } else {
+ inQuote = true
+ }
+ case '\n', '\r', '\t', ' ':
+ if !inQuote {
+ continue
+ }
+ }
+ if inJson {
+ jb = append(jb, bval[0])
+ if parenCnt == 0 {
+ break
+ }
+ }
+ previous = bval[0]
+ }
+
+ return &jb, nil
+}
+
+// ------------------------------- JSON Reader handler via Map values -----------------------
+
+// Default poll delay to keep Handler from spinning on an open stream
+// like sitting on os.Stdin waiting for imput.
+var jhandlerPollInterval = time.Duration(1e6)
+
+// While unnecessary, we make HandleJsonReader() have the same signature as HandleXmlReader().
+// This avoids treating one or other as a special case and discussing the underlying stdlib logic.
+
+// Bulk process JSON using handlers that process a Map value.
+// 'rdr' is an io.Reader for the JSON (stream).
+// 'mapHandler' is the Map processing handler. Return of 'false' stops io.Reader processing.
+// 'errHandler' is the error processor. Return of 'false' stops io.Reader processing and returns the error.
+// Note: mapHandler() and errHandler() calls are blocking, so reading and processing of messages is serialized.
+// This means that you can stop reading the file on error or after processing a particular message.
+// To have reading and handling run concurrently, pass argument to a go routine in handler and return 'true'.
+func HandleJsonReader(jsonReader io.Reader, mapHandler func(Map) bool, errHandler func(error) bool) error {
+ var n int
+ for {
+ m, merr := NewMapJsonReader(jsonReader)
+ n++
+
+ // handle error condition with errhandler
+ if merr != nil && merr != io.EOF {
+ merr = fmt.Errorf("[jsonReader: %d] %s", n, merr.Error())
+ if ok := errHandler(merr); !ok {
+ // caused reader termination
+ return merr
+ }
+ continue
+ }
+
+ // pass to maphandler
+ if len(m) != 0 {
+ if ok := mapHandler(m); !ok {
+ break
+ }
+ } else if merr != io.EOF {
+ <-time.After(jhandlerPollInterval)
+ }
+
+ if merr == io.EOF {
+ break
+ }
+ }
+ return nil
+}
+
+// Bulk process JSON using handlers that process a Map value and the raw JSON.
+// 'rdr' is an io.Reader for the JSON (stream).
+// 'mapHandler' is the Map and raw JSON - []byte - processor. Return of 'false' stops io.Reader processing.
+// 'errHandler' is the error and raw JSON processor. Return of 'false' stops io.Reader processing and returns the error.
+// Note: mapHandler() and errHandler() calls are blocking, so reading and processing of messages is serialized.
+// This means that you can stop reading the file on error or after processing a particular message.
+// To have reading and handling run concurrently, pass argument(s) to a go routine in handler and return 'true'.
+func HandleJsonReaderRaw(jsonReader io.Reader, mapHandler func(Map, []byte) bool, errHandler func(error, []byte) bool) error {
+ var n int
+ for {
+ m, raw, merr := NewMapJsonReaderRaw(jsonReader)
+ n++
+
+ // handle error condition with errhandler
+ if merr != nil && merr != io.EOF {
+ merr = fmt.Errorf("[jsonReader: %d] %s", n, merr.Error())
+ if ok := errHandler(merr, raw); !ok {
+ // caused reader termination
+ return merr
+ }
+ continue
+ }
+
+ // pass to maphandler
+ if len(m) != 0 {
+ if ok := mapHandler(m, raw); !ok {
+ break
+ }
+ } else if merr != io.EOF {
+ <-time.After(jhandlerPollInterval)
+ }
+
+ if merr == io.EOF {
+ break
+ }
+ }
+ return nil
+}
diff --git a/vendor/github.com/clbanning/mxj/keyvalues.go b/vendor/github.com/clbanning/mxj/keyvalues.go
new file mode 100644
index 0000000..0b244c8
--- /dev/null
+++ b/vendor/github.com/clbanning/mxj/keyvalues.go
@@ -0,0 +1,671 @@
+// Copyright 2012-2014 Charles Banning. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file
+
+// keyvalues.go: Extract values from an arbitrary XML doc. Tag path can include wildcard characters.
+
+package mxj
+
+import (
+ "errors"
+ "fmt"
+ "strconv"
+ "strings"
+)
+
+// ----------------------------- get everything FOR a single key -------------------------
+
+const (
+ minArraySize = 32
+)
+
+var defaultArraySize int = minArraySize
+
+// Adjust the buffers for expected number of values to return from ValuesForKey() and ValuesForPath().
+// This can have the effect of significantly reducing memory allocation-copy functions for large data sets.
+// Returns the initial buffer size.
+func SetArraySize(size int) int {
+ if size > minArraySize {
+ defaultArraySize = size
+ } else {
+ defaultArraySize = minArraySize
+ }
+ return defaultArraySize
+}
+
+// Return all values in Map, 'mv', associated with a 'key'. If len(returned_values) == 0, then no match.
+// On error, the returned slice is 'nil'. NOTE: 'key' can be wildcard, "*".
+// 'subkeys' (optional) are "key:val[:type]" strings representing attributes or elements in a list.
+// - By default 'val' is of type string. "key:val:bool" and "key:val:float" to coerce them.
+// - For attributes prefix the label with a hyphen, '-', e.g., "-seq:3".
+// - If the 'key' refers to a list, then "key:value" could select a list member of the list.
+// - The subkey can be wildcarded - "key:*" - to require that it's there with some value.
+// - If a subkey is preceeded with the '!' character, the key:value[:type] entry is treated as an
+// exclusion critera - e.g., "!author:William T. Gaddis".
+// - If val contains ":" symbol, use SetFieldSeparator to a unused symbol, perhaps "|".
+func (mv Map) ValuesForKey(key string, subkeys ...string) ([]interface{}, error) {
+ m := map[string]interface{}(mv)
+ var subKeyMap map[string]interface{}
+ if len(subkeys) > 0 {
+ var err error
+ subKeyMap, err = getSubKeyMap(subkeys...)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ ret := make([]interface{}, 0, defaultArraySize)
+ var cnt int
+ hasKey(m, key, &ret, &cnt, subKeyMap)
+ return ret[:cnt], nil
+}
+
+var KeyNotExistError = errors.New("Key does not exist")
+
+// ValueForKey is a wrapper on ValuesForKey. It returns the first member of []interface{}, if any.
+// If there is no value, "nil, nil" is returned.
+func (mv Map) ValueForKey(key string, subkeys ...string) (interface{}, error) {
+ vals, err := mv.ValuesForKey(key, subkeys...)
+ if err != nil {
+ return nil, err
+ }
+ if len(vals) == 0 {
+ return nil, KeyNotExistError
+ }
+ return vals[0], nil
+}
+
+// hasKey - if the map 'key' exists append it to array
+// if it doesn't do nothing except scan array and map values
+func hasKey(iv interface{}, key string, ret *[]interface{}, cnt *int, subkeys map[string]interface{}) {
+ // func hasKey(iv interface{}, key string, ret *[]interface{}, subkeys map[string]interface{}) {
+ switch iv.(type) {
+ case map[string]interface{}:
+ vv := iv.(map[string]interface{})
+ // see if the current value is of interest
+ if v, ok := vv[key]; ok {
+ switch v.(type) {
+ case map[string]interface{}:
+ if hasSubKeys(v, subkeys) {
+ *ret = append(*ret, v)
+ *cnt++
+ }
+ case []interface{}:
+ for _, av := range v.([]interface{}) {
+ if hasSubKeys(av, subkeys) {
+ *ret = append(*ret, av)
+ *cnt++
+ }
+ }
+ default:
+ if len(subkeys) == 0 {
+ *ret = append(*ret, v)
+ *cnt++
+ }
+ }
+ }
+
+ // wildcard case
+ if key == "*" {
+ for _, v := range vv {
+ switch v.(type) {
+ case map[string]interface{}:
+ if hasSubKeys(v, subkeys) {
+ *ret = append(*ret, v)
+ *cnt++
+ }
+ case []interface{}:
+ for _, av := range v.([]interface{}) {
+ if hasSubKeys(av, subkeys) {
+ *ret = append(*ret, av)
+ *cnt++
+ }
+ }
+ default:
+ if len(subkeys) == 0 {
+ *ret = append(*ret, v)
+ *cnt++
+ }
+ }
+ }
+ }
+
+ // scan the rest
+ for _, v := range vv {
+ hasKey(v, key, ret, cnt, subkeys)
+ }
+ case []interface{}:
+ for _, v := range iv.([]interface{}) {
+ hasKey(v, key, ret, cnt, subkeys)
+ }
+ }
+}
+
+// ----------------------- get everything for a node in the Map ---------------------------
+
+// Allow indexed arrays in "path" specification. (Request from Abhijit Kadam - abhijitk100@gmail.com.)
+// 2014.04.28 - implementation note.
+// Implemented as a wrapper of (old)ValuesForPath() because we need look-ahead logic to handle expansion
+// of wildcards and unindexed arrays. Embedding such logic into valuesForKeyPath() would have made the
+// code much more complicated; this wrapper is straightforward, easy to debug, and doesn't add significant overhead.
+
+// Retrieve all values for a path from the Map. If len(returned_values) == 0, then no match.
+// On error, the returned array is 'nil'.
+// 'path' is a dot-separated path of key values.
+// - If a node in the path is '*', then everything beyond is walked.
+// - 'path' can contain indexed array references, such as, "*.data[1]" and "msgs[2].data[0].field" -
+// even "*[2].*[0].field".
+// 'subkeys' (optional) are "key:val[:type]" strings representing attributes or elements in a list.
+// - By default 'val' is of type string. "key:val:bool" and "key:val:float" to coerce them.
+// - For attributes prefix the label with a hyphen, '-', e.g., "-seq:3".
+// - If the 'path' refers to a list, then "tag:value" would return member of the list.
+// - The subkey can be wildcarded - "key:*" - to require that it's there with some value.
+// - If a subkey is preceeded with the '!' character, the key:value[:type] entry is treated as an
+// exclusion critera - e.g., "!author:William T. Gaddis".
+// - If val contains ":" symbol, use SetFieldSeparator to a unused symbol, perhaps "|".
+func (mv Map) ValuesForPath(path string, subkeys ...string) ([]interface{}, error) {
+ // If there are no array indexes in path, use legacy ValuesForPath() logic.
+ if strings.Index(path, "[") < 0 {
+ return mv.oldValuesForPath(path, subkeys...)
+ }
+
+ var subKeyMap map[string]interface{}
+ if len(subkeys) > 0 {
+ var err error
+ subKeyMap, err = getSubKeyMap(subkeys...)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ keys, kerr := parsePath(path)
+ if kerr != nil {
+ return nil, kerr
+ }
+
+ vals, verr := valuesForArray(keys, mv)
+ if verr != nil {
+ return nil, verr // Vals may be nil, but return empty array.
+ }
+
+ // Need to handle subkeys ... only return members of vals that satisfy conditions.
+ retvals := make([]interface{}, 0)
+ for _, v := range vals {
+ if hasSubKeys(v, subKeyMap) {
+ retvals = append(retvals, v)
+ }
+ }
+ return retvals, nil
+}
+
+func valuesForArray(keys []*key, m Map) ([]interface{}, error) {
+ var tmppath string
+ var haveFirst bool
+ var vals []interface{}
+ var verr error
+
+ lastkey := len(keys) - 1
+ for i := 0; i <= lastkey; i++ {
+ if !haveFirst {
+ tmppath = keys[i].name
+ haveFirst = true
+ } else {
+ tmppath += "." + keys[i].name
+ }
+
+ // Look-ahead: explode wildcards and unindexed arrays.
+ // Need to handle un-indexed list recursively:
+ // e.g., path is "stuff.data[0]" rather than "stuff[0].data[0]".
+ // Need to treat it as "stuff[0].data[0]", "stuff[1].data[0]", ...
+ if !keys[i].isArray && i < lastkey && keys[i+1].isArray {
+ // Can't pass subkeys because we may not be at literal end of path.
+ vv, vverr := m.oldValuesForPath(tmppath)
+ if vverr != nil {
+ return nil, vverr
+ }
+ for _, v := range vv {
+ // See if we can walk the value.
+ am, ok := v.(map[string]interface{})
+ if !ok {
+ continue
+ }
+ // Work the backend.
+ nvals, nvalserr := valuesForArray(keys[i+1:], Map(am))
+ if nvalserr != nil {
+ return nil, nvalserr
+ }
+ vals = append(vals, nvals...)
+ }
+ break // have recursed the whole path - return
+ }
+
+ if keys[i].isArray || i == lastkey {
+ // Don't pass subkeys because may not be at literal end of path.
+ vals, verr = m.oldValuesForPath(tmppath)
+ } else {
+ continue
+ }
+ if verr != nil {
+ return nil, verr
+ }
+
+ if i == lastkey && !keys[i].isArray {
+ break
+ }
+
+ // Now we're looking at an array - supposedly.
+ // Is index in range of vals?
+ if len(vals) <= keys[i].position {
+ vals = nil
+ break
+ }
+
+ // Return the array member of interest, if at end of path.
+ if i == lastkey {
+ vals = vals[keys[i].position:(keys[i].position + 1)]
+ break
+ }
+
+ // Extract the array member of interest.
+ am := vals[keys[i].position:(keys[i].position + 1)]
+
+ // must be a map[string]interface{} value so we can keep walking the path
+ amm, ok := am[0].(map[string]interface{})
+ if !ok {
+ vals = nil
+ break
+ }
+
+ m = Map(amm)
+ haveFirst = false
+ }
+
+ return vals, nil
+}
+
+type key struct {
+ name string
+ isArray bool
+ position int
+}
+
+func parsePath(s string) ([]*key, error) {
+ keys := strings.Split(s, ".")
+
+ ret := make([]*key, 0)
+
+ for i := 0; i < len(keys); i++ {
+ if keys[i] == "" {
+ continue
+ }
+
+ newkey := new(key)
+ if strings.Index(keys[i], "[") < 0 {
+ newkey.name = keys[i]
+ ret = append(ret, newkey)
+ continue
+ }
+
+ p := strings.Split(keys[i], "[")
+ newkey.name = p[0]
+ p = strings.Split(p[1], "]")
+ if p[0] == "" { // no right bracket
+ return nil, fmt.Errorf("no right bracket on key index: %s", keys[i])
+ }
+ // convert p[0] to a int value
+ pos, nerr := strconv.ParseInt(p[0], 10, 32)
+ if nerr != nil {
+ return nil, fmt.Errorf("cannot convert index to int value: %s", p[0])
+ }
+ newkey.position = int(pos)
+ newkey.isArray = true
+ ret = append(ret, newkey)
+ }
+
+ return ret, nil
+}
+
+// legacy ValuesForPath() - now wrapped to handle special case of indexed arrays in 'path'.
+func (mv Map) oldValuesForPath(path string, subkeys ...string) ([]interface{}, error) {
+ m := map[string]interface{}(mv)
+ var subKeyMap map[string]interface{}
+ if len(subkeys) > 0 {
+ var err error
+ subKeyMap, err = getSubKeyMap(subkeys...)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ keys := strings.Split(path, ".")
+ if keys[len(keys)-1] == "" {
+ keys = keys[:len(keys)-1]
+ }
+ ivals := make([]interface{}, 0, defaultArraySize)
+ var cnt int
+ valuesForKeyPath(&ivals, &cnt, m, keys, subKeyMap)
+ return ivals[:cnt], nil
+}
+
+func valuesForKeyPath(ret *[]interface{}, cnt *int, m interface{}, keys []string, subkeys map[string]interface{}) {
+ lenKeys := len(keys)
+
+ // load 'm' values into 'ret'
+ // expand any lists
+ if lenKeys == 0 {
+ switch m.(type) {
+ case map[string]interface{}:
+ if subkeys != nil {
+ if ok := hasSubKeys(m, subkeys); !ok {
+ return
+ }
+ }
+ *ret = append(*ret, m)
+ *cnt++
+ case []interface{}:
+ for i, v := range m.([]interface{}) {
+ if subkeys != nil {
+ if ok := hasSubKeys(v, subkeys); !ok {
+ continue // only load list members with subkeys
+ }
+ }
+ *ret = append(*ret, (m.([]interface{}))[i])
+ *cnt++
+ }
+ default:
+ if subkeys != nil {
+ return // must be map[string]interface{} if there are subkeys
+ }
+ *ret = append(*ret, m)
+ *cnt++
+ }
+ return
+ }
+
+ // key of interest
+ key := keys[0]
+ switch key {
+ case "*": // wildcard - scan all values
+ switch m.(type) {
+ case map[string]interface{}:
+ for _, v := range m.(map[string]interface{}) {
+ // valuesForKeyPath(ret, v, keys[1:], subkeys)
+ valuesForKeyPath(ret, cnt, v, keys[1:], subkeys)
+ }
+ case []interface{}:
+ for _, v := range m.([]interface{}) {
+ switch v.(type) {
+ // flatten out a list of maps - keys are processed
+ case map[string]interface{}:
+ for _, vv := range v.(map[string]interface{}) {
+ // valuesForKeyPath(ret, vv, keys[1:], subkeys)
+ valuesForKeyPath(ret, cnt, vv, keys[1:], subkeys)
+ }
+ default:
+ // valuesForKeyPath(ret, v, keys[1:], subkeys)
+ valuesForKeyPath(ret, cnt, v, keys[1:], subkeys)
+ }
+ }
+ }
+ default: // key - must be map[string]interface{}
+ switch m.(type) {
+ case map[string]interface{}:
+ if v, ok := m.(map[string]interface{})[key]; ok {
+ // valuesForKeyPath(ret, v, keys[1:], subkeys)
+ valuesForKeyPath(ret, cnt, v, keys[1:], subkeys)
+ }
+ case []interface{}: // may be buried in list
+ for _, v := range m.([]interface{}) {
+ switch v.(type) {
+ case map[string]interface{}:
+ if vv, ok := v.(map[string]interface{})[key]; ok {
+ // valuesForKeyPath(ret, vv, keys[1:], subkeys)
+ valuesForKeyPath(ret, cnt, vv, keys[1:], subkeys)
+ }
+ }
+ }
+ }
+ }
+}
+
+// hasSubKeys() - interface{} equality works for string, float64, bool
+// 'v' must be a map[string]interface{} value to have subkeys
+// 'a' can have k:v pairs with v.(string) == "*", which is treated like a wildcard.
+func hasSubKeys(v interface{}, subkeys map[string]interface{}) bool {
+ if len(subkeys) == 0 {
+ return true
+ }
+
+ switch v.(type) {
+ case map[string]interface{}:
+ // do all subKey name:value pairs match?
+ mv := v.(map[string]interface{})
+ for skey, sval := range subkeys {
+ isNotKey := false
+ if skey[:1] == "!" { // a NOT-key
+ skey = skey[1:]
+ isNotKey = true
+ }
+ vv, ok := mv[skey]
+ if !ok { // key doesn't exist
+ if isNotKey { // key not there, but that's what we want
+ if kv, ok := sval.(string); ok && kv == "*" {
+ continue
+ }
+ }
+ return false
+ }
+ // wildcard check
+ if kv, ok := sval.(string); ok && kv == "*" {
+ if isNotKey { // key is there, and we don't want it
+ return false
+ }
+ continue
+ }
+ switch sval.(type) {
+ case string:
+ if s, ok := vv.(string); ok && s == sval.(string) {
+ if isNotKey {
+ return false
+ }
+ continue
+ }
+ case bool:
+ if b, ok := vv.(bool); ok && b == sval.(bool) {
+ if isNotKey {
+ return false
+ }
+ continue
+ }
+ case float64:
+ if f, ok := vv.(float64); ok && f == sval.(float64) {
+ if isNotKey {
+ return false
+ }
+ continue
+ }
+ }
+ // key there but didn't match subkey value
+ if isNotKey { // that's what we want
+ continue
+ }
+ return false
+ }
+ // all subkeys matched
+ return true
+ }
+
+ // not a map[string]interface{} value, can't have subkeys
+ return false
+}
+
+// Generate map of key:value entries as map[string]string.
+// 'kv' arguments are "name:value" pairs: attribute keys are designated with prepended hyphen, '-'.
+// If len(kv) == 0, the return is (nil, nil).
+func getSubKeyMap(kv ...string) (map[string]interface{}, error) {
+ if len(kv) == 0 {
+ return nil, nil
+ }
+ m := make(map[string]interface{}, 0)
+ for _, v := range kv {
+ vv := strings.Split(v, fieldSep)
+ switch len(vv) {
+ case 2:
+ m[vv[0]] = interface{}(vv[1])
+ case 3:
+ switch vv[2] {
+ case "string", "char", "text":
+ m[vv[0]] = interface{}(vv[1])
+ case "bool", "boolean":
+ // ParseBool treats "1"==true & "0"==false
+ b, err := strconv.ParseBool(vv[1])
+ if err != nil {
+ return nil, fmt.Errorf("can't convert subkey value to bool: %s", vv[1])
+ }
+ m[vv[0]] = interface{}(b)
+ case "float", "float64", "num", "number", "numeric":
+ f, err := strconv.ParseFloat(vv[1], 64)
+ if err != nil {
+ return nil, fmt.Errorf("can't convert subkey value to float: %s", vv[1])
+ }
+ m[vv[0]] = interface{}(f)
+ default:
+ return nil, fmt.Errorf("unknown subkey conversion spec: %s", v)
+ }
+ default:
+ return nil, fmt.Errorf("unknown subkey spec: %s", v)
+ }
+ }
+ return m, nil
+}
+
+// ------------------------------- END of valuesFor ... ----------------------------
+
+// ----------------------- locate where a key value is in the tree -------------------
+
+//----------------------------- find all paths to a key --------------------------------
+
+// Get all paths through Map, 'mv', (in dot-notation) that terminate with the specified key.
+// Results can be used with ValuesForPath.
+func (mv Map) PathsForKey(key string) []string {
+ m := map[string]interface{}(mv)
+ breadbasket := make(map[string]bool, 0)
+ breadcrumbs := ""
+
+ hasKeyPath(breadcrumbs, m, key, breadbasket)
+ if len(breadbasket) == 0 {
+ return nil
+ }
+
+ // unpack map keys to return
+ res := make([]string, len(breadbasket))
+ var i int
+ for k := range breadbasket {
+ res[i] = k
+ i++
+ }
+
+ return res
+}
+
+// Extract the shortest path from all possible paths - from PathsForKey() - in Map, 'mv'..
+// Paths are strings using dot-notation.
+func (mv Map) PathForKeyShortest(key string) string {
+ paths := mv.PathsForKey(key)
+
+ lp := len(paths)
+ if lp == 0 {
+ return ""
+ }
+ if lp == 1 {
+ return paths[0]
+ }
+
+ shortest := paths[0]
+ shortestLen := len(strings.Split(shortest, "."))
+
+ for i := 1; i < len(paths); i++ {
+ vlen := len(strings.Split(paths[i], "."))
+ if vlen < shortestLen {
+ shortest = paths[i]
+ shortestLen = vlen
+ }
+ }
+
+ return shortest
+}
+
+// hasKeyPath - if the map 'key' exists append it to KeyPath.path and increment KeyPath.depth
+// This is really just a breadcrumber that saves all trails that hit the prescribed 'key'.
+func hasKeyPath(crumbs string, iv interface{}, key string, basket map[string]bool) {
+ switch iv.(type) {
+ case map[string]interface{}:
+ vv := iv.(map[string]interface{})
+ if _, ok := vv[key]; ok {
+ // create a new breadcrumb, intialized with the one we have
+ var nbc string
+ if crumbs == "" {
+ nbc = key
+ } else {
+ nbc = crumbs + "." + key
+ }
+ basket[nbc] = true
+ }
+ // walk on down the path, key could occur again at deeper node
+ for k, v := range vv {
+ // create a new breadcrumb, intialized with the one we have
+ var nbc string
+ if crumbs == "" {
+ nbc = k
+ } else {
+ nbc = crumbs + "." + k
+ }
+ hasKeyPath(nbc, v, key, basket)
+ }
+ case []interface{}:
+ // crumb-trail doesn't change, pass it on
+ for _, v := range iv.([]interface{}) {
+ hasKeyPath(crumbs, v, key, basket)
+ }
+ }
+}
+
+var PathNotExistError = errors.New("Path does not exist")
+
+// ValueForPath wrap ValuesFor Path and returns the first value returned.
+// If no value is found it returns 'nil' and PathNotExistError.
+func (mv Map) ValueForPath(path string) (interface{}, error) {
+ vals, err := mv.ValuesForPath(path)
+ if err != nil {
+ return nil, err
+ }
+ if len(vals) == 0 {
+ return nil, PathNotExistError
+ }
+ return vals[0], nil
+}
+
+// Returns the first found value for the path as a string.
+func (mv Map) ValueForPathString(path string) (string, error) {
+ vals, err := mv.ValuesForPath(path)
+ if err != nil {
+ return "", err
+ }
+ if len(vals) == 0 {
+ return "", errors.New("ValueForPath: path not found")
+ }
+ val := vals[0]
+ switch str := val.(type) {
+ case string:
+ return str, nil
+ default:
+ return "", fmt.Errorf("ValueForPath: unsupported type: %T", str)
+ }
+}
+
+// Returns the first found value for the path as a string.
+// If the path is not found then it returns an empty string.
+func (mv Map) ValueOrEmptyForPathString(path string) string {
+ str, _ := mv.ValueForPathString(path)
+ return str
+}
diff --git a/vendor/github.com/clbanning/mxj/leafnode.go b/vendor/github.com/clbanning/mxj/leafnode.go
new file mode 100644
index 0000000..cf413eb
--- /dev/null
+++ b/vendor/github.com/clbanning/mxj/leafnode.go
@@ -0,0 +1,112 @@
+package mxj
+
+// leafnode.go - return leaf nodes with paths and values for the Map
+// inspired by: https://groups.google.com/forum/#!topic/golang-nuts/3JhuVKRuBbw
+
+import (
+ "strconv"
+ "strings"
+)
+
+const (
+ NoAttributes = true // suppress LeafNode values that are attributes
+)
+
+// LeafNode - a terminal path value in a Map.
+// For XML Map values it represents an attribute or simple element value - of type
+// string unless Map was created using Cast flag. For JSON Map values it represents
+// a string, numeric, boolean, or null value.
+type LeafNode struct {
+ Path string // a dot-notation representation of the path with array subscripting
+ Value interface{} // the value at the path termination
+}
+
+// LeafNodes - returns an array of all LeafNode values for the Map.
+// The option no_attr argument suppresses attribute values (keys with prepended hyphen, '-')
+// as well as the "#text" key for the associated simple element value.
+//
+// PrependAttrWithHypen(false) will result in attributes having .attr-name as
+// terminal node in 'path' while the path for the element value, itself, will be
+// the base path w/o "#text".
+//
+// LeafUseDotNotation(true) causes list members to be identified using ".N" syntax
+// rather than "[N]" syntax.
+func (mv Map) LeafNodes(no_attr ...bool) []LeafNode {
+ var a bool
+ if len(no_attr) == 1 {
+ a = no_attr[0]
+ }
+
+ l := make([]LeafNode, 0)
+ getLeafNodes("", "", map[string]interface{}(mv), &l, a)
+ return l
+}
+
+func getLeafNodes(path, node string, mv interface{}, l *[]LeafNode, noattr bool) {
+ // if stripping attributes, then also strip "#text" key
+ if !noattr || node != "#text" {
+ if path != "" && node[:1] != "[" {
+ path += "."
+ }
+ path += node
+ }
+ switch mv.(type) {
+ case map[string]interface{}:
+ for k, v := range mv.(map[string]interface{}) {
+ // if noattr && k[:1] == "-" {
+ if noattr && len(attrPrefix) > 0 && strings.Index(k, attrPrefix) == 0 {
+ continue
+ }
+ getLeafNodes(path, k, v, l, noattr)
+ }
+ case []interface{}:
+ for i, v := range mv.([]interface{}) {
+ if useDotNotation {
+ getLeafNodes(path, strconv.Itoa(i), v, l, noattr)
+ } else {
+ getLeafNodes(path, "["+strconv.Itoa(i)+"]", v, l, noattr)
+ }
+ }
+ default:
+ // can't walk any further, so create leaf
+ n := LeafNode{path, mv}
+ *l = append(*l, n)
+ }
+}
+
+// LeafPaths - all paths that terminate in LeafNode values.
+func (mv Map) LeafPaths(no_attr ...bool) []string {
+ ln := mv.LeafNodes()
+ ss := make([]string, len(ln))
+ for i := 0; i < len(ln); i++ {
+ ss[i] = ln[i].Path
+ }
+ return ss
+}
+
+// LeafValues - all terminal values in the Map.
+func (mv Map) LeafValues(no_attr ...bool) []interface{} {
+ ln := mv.LeafNodes()
+ vv := make([]interface{}, len(ln))
+ for i := 0; i < len(ln); i++ {
+ vv[i] = ln[i].Value
+ }
+ return vv
+}
+
+// ====================== utilities ======================
+
+// https://groups.google.com/forum/#!topic/golang-nuts/pj0C5IrZk4I
+var useDotNotation bool
+
+// LeafUseDotNotation sets a flag that list members in LeafNode paths
+// should be identified using ".N" syntax rather than the default "[N]"
+// syntax. Calling LeafUseDotNotation with no arguments toggles the
+// flag on/off; otherwise, the argument sets the flag value 'true'/'false'.
+func LeafUseDotNotation(b ...bool) {
+ if len(b) == 0 {
+ useDotNotation = !useDotNotation
+ return
+ }
+ useDotNotation = b[0]
+}
diff --git a/vendor/github.com/clbanning/mxj/misc.go b/vendor/github.com/clbanning/mxj/misc.go
new file mode 100644
index 0000000..5b4fab2
--- /dev/null
+++ b/vendor/github.com/clbanning/mxj/misc.go
@@ -0,0 +1,86 @@
+// Copyright 2016 Charles Banning. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file
+
+// misc.go - mimic functions (+others) called out in:
+// https://groups.google.com/forum/#!topic/golang-nuts/jm_aGsJNbdQ
+// Primarily these methods let you retrive XML structure information.
+
+package mxj
+
+import (
+ "fmt"
+ "sort"
+ "strings"
+)
+
+// Return the root element of the Map. If there is not a single key in Map,
+// then an error is returned.
+func (mv Map) Root() (string, error) {
+ mm := map[string]interface{}(mv)
+ if len(mm) != 1 {
+ return "", fmt.Errorf("Map does not have singleton root. Len: %d.", len(mm))
+ }
+ for k, _ := range mm {
+ return k, nil
+ }
+ return "", nil
+}
+
+// If the path is an element with sub-elements, return a list of the sub-element
+// keys. (The list is alphabeticly sorted.) NOTE: Map keys that are prefixed with
+// '-', a hyphen, are considered attributes; see m.Attributes(path).
+func (mv Map) Elements(path string) ([]string, error) {
+ e, err := mv.ValueForPath(path)
+ if err != nil {
+ return nil, err
+ }
+ switch e.(type) {
+ case map[string]interface{}:
+ ee := e.(map[string]interface{})
+ elems := make([]string, len(ee))
+ var i int
+ for k, _ := range ee {
+ if len(attrPrefix) > 0 && strings.Index(k, attrPrefix) == 0 {
+ continue // skip attributes
+ }
+ elems[i] = k
+ i++
+ }
+ elems = elems[:i]
+ // alphabetic sort keeps things tidy
+ sort.Strings(elems)
+ return elems, nil
+ }
+ return nil, fmt.Errorf("no elements for path: %s", path)
+}
+
+// If the path is an element with attributes, return a list of the attribute
+// keys. (The list is alphabeticly sorted.) NOTE: Map keys that are not prefixed with
+// '-', a hyphen, are not treated as attributes; see m.Elements(path). Also, if the
+// attribute prefix is "" - SetAttrPrefix("") or PrependAttrWithHyphen(false) - then
+// there are no identifiable attributes.
+func (mv Map) Attributes(path string) ([]string, error) {
+ a, err := mv.ValueForPath(path)
+ if err != nil {
+ return nil, err
+ }
+ switch a.(type) {
+ case map[string]interface{}:
+ aa := a.(map[string]interface{})
+ attrs := make([]string, len(aa))
+ var i int
+ for k, _ := range aa {
+ if len(attrPrefix) == 0 || strings.Index(k, attrPrefix) != 0 {
+ continue // skip non-attributes
+ }
+ attrs[i] = k[len(attrPrefix):]
+ i++
+ }
+ attrs = attrs[:i]
+ // alphabetic sort keeps things tidy
+ sort.Strings(attrs)
+ return attrs, nil
+ }
+ return nil, fmt.Errorf("no attributes for path: %s", path)
+}
diff --git a/vendor/github.com/clbanning/mxj/mxj.go b/vendor/github.com/clbanning/mxj/mxj.go
new file mode 100644
index 0000000..f0592f0
--- /dev/null
+++ b/vendor/github.com/clbanning/mxj/mxj.go
@@ -0,0 +1,128 @@
+// mxj - A collection of map[string]interface{} and associated XML and JSON utilities.
+// Copyright 2012-2014 Charles Banning. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file
+
+package mxj
+
+import (
+ "fmt"
+ "sort"
+)
+
+const (
+ Cast = true // for clarity - e.g., mxj.NewMapXml(doc, mxj.Cast)
+ SafeEncoding = true // ditto - e.g., mv.Json(mxj.SafeEncoding)
+)
+
+type Map map[string]interface{}
+
+// Allocate a Map.
+func New() Map {
+ m := make(map[string]interface{}, 0)
+ return m
+}
+
+// Cast a Map to map[string]interface{}
+func (mv Map) Old() map[string]interface{} {
+ return mv
+}
+
+// Return a copy of mv as a newly allocated Map. If the Map only contains string,
+// numeric, map[string]interface{}, and []interface{} values, then it can be thought
+// of as a "deep copy." Copying a structure (or structure reference) value is subject
+// to the noted restrictions.
+// NOTE: If 'mv' includes structure values with, possibly, JSON encoding tags
+// then only public fields of the structure are in the new Map - and with
+// keys that conform to any encoding tag instructions. The structure itself will
+// be represented as a map[string]interface{} value.
+func (mv Map) Copy() (Map, error) {
+ // this is the poor-man's deep copy
+ // not efficient, but it works
+ j, jerr := mv.Json()
+ // must handle, we don't know how mv got built
+ if jerr != nil {
+ return nil, jerr
+ }
+ return NewMapJson(j)
+}
+
+// --------------- StringIndent ... from x2j.WriteMap -------------
+
+// Pretty print a Map.
+func (mv Map) StringIndent(offset ...int) string {
+ return writeMap(map[string]interface{}(mv), true, true, offset...)
+}
+
+// Pretty print a Map without the value type information - just key:value entries.
+func (mv Map) StringIndentNoTypeInfo(offset ...int) string {
+ return writeMap(map[string]interface{}(mv), false, true, offset...)
+}
+
+// writeMap - dumps the map[string]interface{} for examination.
+// 'typeInfo' causes value type to be printed.
+// 'offset' is initial indentation count; typically: Write(m).
+func writeMap(m interface{}, typeInfo, root bool, offset ...int) string {
+ var indent int
+ if len(offset) == 1 {
+ indent = offset[0]
+ }
+
+ var s string
+ switch m.(type) {
+ case []interface{}:
+ if typeInfo {
+ s += "[[]interface{}]"
+ }
+ for _, v := range m.([]interface{}) {
+ s += "\n"
+ for i := 0; i < indent; i++ {
+ s += " "
+ }
+ s += writeMap(v, typeInfo, false, indent+1)
+ }
+ case map[string]interface{}:
+ list := make([][2]string, len(m.(map[string]interface{})))
+ var n int
+ for k, v := range m.(map[string]interface{}) {
+ list[n][0] = k
+ list[n][1] = writeMap(v, typeInfo, false, indent+1)
+ n++
+ }
+ sort.Sort(mapList(list))
+ for _, v := range list {
+ if root {
+ root = false
+ } else {
+ s += "\n"
+ }
+ for i := 0; i < indent; i++ {
+ s += " "
+ }
+ s += v[0] + " : " + v[1]
+ }
+ default:
+ if typeInfo {
+ s += fmt.Sprintf("[%T] %+v", m, m)
+ } else {
+ s += fmt.Sprintf("%+v", m)
+ }
+ }
+ return s
+}
+
+// ======================== utility ===============
+
+type mapList [][2]string
+
+func (ml mapList) Len() int {
+ return len(ml)
+}
+
+func (ml mapList) Swap(i, j int) {
+ ml[i], ml[j] = ml[j], ml[i]
+}
+
+func (ml mapList) Less(i, j int) bool {
+ return ml[i][0] <= ml[j][0]
+}
diff --git a/vendor/github.com/clbanning/mxj/newmap.go b/vendor/github.com/clbanning/mxj/newmap.go
new file mode 100644
index 0000000..b293949
--- /dev/null
+++ b/vendor/github.com/clbanning/mxj/newmap.go
@@ -0,0 +1,184 @@
+// mxj - A collection of map[string]interface{} and associated XML and JSON utilities.
+// Copyright 2012-2014, 2018 Charles Banning. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file
+
+// remap.go - build a new Map from the current Map based on keyOld:keyNew mapppings
+// keys can use dot-notation, keyOld can use wildcard, '*'
+//
+// Computational strategy -
+// Using the key path - []string - traverse a new map[string]interface{} and
+// insert the oldVal as the newVal when we arrive at the end of the path.
+// If the type at the end is nil, then that is newVal
+// If the type at the end is a singleton (string, float64, bool) an array is created.
+// If the type at the end is an array, newVal is just appended.
+// If the type at the end is a map, it is inserted if possible or the map value
+// is converted into an array if necessary.
+
+package mxj
+
+import (
+ "errors"
+ "strings"
+)
+
+// (Map)NewMap - create a new Map from data in the current Map.
+// 'keypairs' are key mappings "oldKey:newKey" and specify that the current value of 'oldKey'
+// should be the value for 'newKey' in the returned Map.
+// - 'oldKey' supports dot-notation as described for (Map)ValuesForPath()
+// - 'newKey' supports dot-notation but with no wildcards, '*', or indexed arrays
+// - "oldKey" is shorthand for the keypair value "oldKey:oldKey"
+// - "oldKey:" and ":newKey" are invalid keypair values
+// - if 'oldKey' does not exist in the current Map, it is not written to the new Map.
+// "null" is not supported unless it is the current Map.
+// - see newmap_test.go for several syntax examples
+// - mv.NewMap() == mxj.New()
+//
+// NOTE: "examples/partial.go" shows how to create arbitrary sub-docs of an XML doc.
+func (mv Map) NewMap(keypairs ...string) (Map, error) {
+ n := make(map[string]interface{}, 0)
+ if len(keypairs) == 0 {
+ return n, nil
+ }
+
+ // loop through the pairs
+ var oldKey, newKey string
+ var path []string
+ for _, v := range keypairs {
+ if len(v) == 0 {
+ continue // just skip over empty keypair arguments
+ }
+
+ // initialize oldKey, newKey and check
+ vv := strings.Split(v, ":")
+ if len(vv) > 2 {
+ return n, errors.New("oldKey:newKey keypair value not valid - " + v)
+ }
+ if len(vv) == 1 {
+ oldKey, newKey = vv[0], vv[0]
+ } else {
+ oldKey, newKey = vv[0], vv[1]
+ }
+ strings.TrimSpace(oldKey)
+ strings.TrimSpace(newKey)
+ if i := strings.Index(newKey, "*"); i > -1 {
+ return n, errors.New("newKey value cannot contain wildcard character - " + v)
+ }
+ if i := strings.Index(newKey, "["); i > -1 {
+ return n, errors.New("newKey value cannot contain indexed arrays - " + v)
+ }
+ if oldKey == "" || newKey == "" {
+ return n, errors.New("oldKey or newKey is not specified - " + v)
+ }
+
+ // get oldKey value
+ oldVal, err := mv.ValuesForPath(oldKey)
+ if err != nil {
+ return n, err
+ }
+ if len(oldVal) == 0 {
+ continue // oldKey has no value, may not exist in mv
+ }
+
+ // break down path
+ path = strings.Split(newKey, ".")
+ if path[len(path)-1] == "" { // ignore a trailing dot in newKey spec
+ path = path[:len(path)-1]
+ }
+
+ addNewVal(&n, path, oldVal)
+ }
+
+ return n, nil
+}
+
+// navigate 'n' to end of path and add val
+func addNewVal(n *map[string]interface{}, path []string, val []interface{}) {
+ // newVal - either singleton or array
+ var newVal interface{}
+ if len(val) == 1 {
+ newVal = val[0] // is type interface{}
+ } else {
+ newVal = interface{}(val)
+ }
+
+ // walk to the position of interest, create it if necessary
+ m := (*n) // initialize map walker
+ var k string // key for m
+ lp := len(path) - 1 // when to stop looking
+ for i := 0; i < len(path); i++ {
+ k = path[i]
+ if i == lp {
+ break
+ }
+ var nm map[string]interface{} // holds position of next-map
+ switch m[k].(type) {
+ case nil: // need a map for next node in path, so go there
+ nm = make(map[string]interface{}, 0)
+ m[k] = interface{}(nm)
+ m = m[k].(map[string]interface{})
+ case map[string]interface{}:
+ // OK - got somewhere to walk to, go there
+ m = m[k].(map[string]interface{})
+ case []interface{}:
+ // add a map and nm points to new map unless there's already
+ // a map in the array, then nm points there
+ // The placement of the next value in the array is dependent
+ // on the sequence of members - could land on a map or a nil
+ // value first. TODO: how to test this.
+ a := make([]interface{}, 0)
+ var foundmap bool
+ for _, vv := range m[k].([]interface{}) {
+ switch vv.(type) {
+ case nil: // doesn't appear that this occurs, need a test case
+ if foundmap { // use the first one in array
+ a = append(a, vv)
+ continue
+ }
+ nm = make(map[string]interface{}, 0)
+ a = append(a, interface{}(nm))
+ foundmap = true
+ case map[string]interface{}:
+ if foundmap { // use the first one in array
+ a = append(a, vv)
+ continue
+ }
+ nm = vv.(map[string]interface{})
+ a = append(a, vv)
+ foundmap = true
+ default:
+ a = append(a, vv)
+ }
+ }
+ // no map found in array
+ if !foundmap {
+ nm = make(map[string]interface{}, 0)
+ a = append(a, interface{}(nm))
+ }
+ m[k] = interface{}(a) // must insert in map
+ m = nm
+ default: // it's a string, float, bool, etc.
+ aa := make([]interface{}, 0)
+ nm = make(map[string]interface{}, 0)
+ aa = append(aa, m[k], nm)
+ m[k] = interface{}(aa)
+ m = nm
+ }
+ }
+
+ // value is nil, array or a singleton of some kind
+ // initially m.(type) == map[string]interface{}
+ v := m[k]
+ switch v.(type) {
+ case nil: // initialized
+ m[k] = newVal
+ case []interface{}:
+ a := m[k].([]interface{})
+ a = append(a, newVal)
+ m[k] = interface{}(a)
+ default: // v exists:string, float64, bool, map[string]interface, etc.
+ a := make([]interface{}, 0)
+ a = append(a, v, newVal)
+ m[k] = interface{}(a)
+ }
+}
diff --git a/vendor/github.com/clbanning/mxj/readme.md b/vendor/github.com/clbanning/mxj/readme.md
new file mode 100644
index 0000000..6bb21dc
--- /dev/null
+++ b/vendor/github.com/clbanning/mxj/readme.md
@@ -0,0 +1,179 @@
+
mxj - to/from maps, XML and JSON
+Decode/encode XML to/from map[string]interface{} (or JSON) values, and extract/modify values from maps by key or key-path, including wildcards.
+
+mxj supplants the legacy x2j and j2x packages. If you want the old syntax, use mxj/x2j and mxj/j2x packages.
+
+
Related Packages
+
+https://github.com/clbanning/checkxml provides functions for validating XML data.
+
+
Refactor Decoder - 2015.11.15
+For over a year I've wanted to refactor the XML-to-map[string]interface{} decoder to make it more performant. I recently took the time to do that, since we were using github.com/clbanning/mxj in a production system that could be deployed on a Raspberry Pi. Now the decoder is comparable to the stdlib JSON-to-map[string]interface{} decoder in terms of its additional processing overhead relative to decoding to a structure value. As shown by:
+
+ BenchmarkNewMapXml-4 100000 18043 ns/op
+ BenchmarkNewStructXml-4 100000 14892 ns/op
+ BenchmarkNewMapJson-4 300000 4633 ns/op
+ BenchmarkNewStructJson-4 300000 3427 ns/op
+ BenchmarkNewMapXmlBooks-4 20000 82850 ns/op
+ BenchmarkNewStructXmlBooks-4 20000 67822 ns/op
+ BenchmarkNewMapJsonBooks-4 100000 17222 ns/op
+ BenchmarkNewStructJsonBooks-4 100000 15309 ns/op
+
+
Notices
+
+ 2018.04.18: mv.Xml/mv.XmlIndent encodes non-map[string]interface{} map values - map[string]string, map[int]uint, etc.
+ 2018.03.29: mv.Gob/NewMapGob support gob encoding/decoding of Maps.
+ 2018.03.26: Added mxj/x2j-wrapper sub-package for migrating from legacy x2j package.
+ 2017.02.22: LeafNode paths can use ".N" syntax rather than "[N]" for list member indexing.
+ 2017.02.10: SetFieldSeparator changes field separator for args in UpdateValuesForPath, ValuesFor... methods.
+ 2017.02.06: Support XMPP stream processing - HandleXMPPStreamTag().
+ 2016.11.07: Preserve name space prefix syntax in XmlSeq parser - NewMapXmlSeq(), etc.
+ 2016.06.25: Support overriding default XML attribute prefix, "-", in Map keys - SetAttrPrefix().
+ 2016.05.26: Support customization of xml.Decoder by exposing CustomDecoder variable.
+ 2016.03.19: Escape invalid chars when encoding XML attribute and element values - XMLEscapeChars().
+ 2016.03.02: By default decoding XML with float64 and bool value casting will not cast "NaN", "Inf", and "-Inf".
+ To cast them to float64, first set flag with CastNanInf(true).
+ 2016.02.22: New mv.Root(), mv.Elements(), mv.Attributes methods let you examine XML document structure.
+ 2016.02.16: Add CoerceKeysToLower() option to handle tags with mixed capitalization.
+ 2016.02.12: Seek for first xml.StartElement token; only return error if io.EOF is reached first (handles BOM).
+ 2015.12.02: XML decoding/encoding that preserves original structure of document. See NewMapXmlSeq()
+ and mv.XmlSeq() / mv.XmlSeqIndent().
+ 2015-05-20: New: mv.StringIndentNoTypeInfo().
+ Also, alphabetically sort map[string]interface{} values by key to prettify output for mv.Xml(),
+ mv.XmlIndent(), mv.StringIndent(), mv.StringIndentNoTypeInfo().
+ 2014-11-09: IncludeTagSeqNum() adds "_seq" key with XML doc positional information.
+ (NOTE: PreserveXmlList() is similar and will be here soon.)
+ 2014-09-18: inspired by NYTimes fork, added PrependAttrWithHyphen() to allow stripping hyphen from attribute tag.
+ 2014-08-02: AnyXml() and AnyXmlIndent() will try to marshal arbitrary values to XML.
+ 2014-04-28: ValuesForPath() and NewMap() now accept path with indexed array references.
+
+
Basic Unmarshal XML to map[string]interface{}
+
type Map map[string]interface{}
+
+Create a `Map` value, 'mv', from any `map[string]interface{}` value, 'v':
+
mv := Map(v)
+
+Unmarshal / marshal XML as a `Map` value, 'mv':
+
+
+Unmarshal XML from an `io.Reader` as a `Map` value, 'mv':
+
mv, err := NewMapXmlReader(xmlReader) // repeated calls, as with an os.File Reader, will process stream
+mv, raw, err := NewMapXmlReaderRaw(xmlReader) // 'raw' is the raw XML that was decoded
+
+Marshal `Map` value, 'mv', to an XML Writer (`io.Writer`):
+
err := mv.XmlWriter(xmlWriter)
+raw, err := mv.XmlWriterRaw(xmlWriter) // 'raw' is the raw XML that was written on xmlWriter
+
+Converting XML to JSON: see Examples for `NewMapXml` and `HandleXmlReader`.
+
+There are comparable functions and methods for JSON processing.
+
+Arbitrary structure values can be decoded to / encoded from `Map` values:
+
+To work with XML tag values, JSON or Map key values or structure field values, decode the XML, JSON
+or structure to a `Map` value, 'mv', or cast a `map[string]interface{}` value to a `Map` value, 'mv', then:
+
+
+A new `Map` with whatever keys are desired can be created from the current `Map` and then encoded in XML
+or JSON. (Note: keys can use dot-notation.)
+
newMap, err := mv.NewMap("oldKey_1:newKey_1", "oldKey_2:newKey_2", ..., "oldKey_N:newKey_N")
+newMap, err := mv.NewMap("oldKey1", "oldKey3", "oldKey5") // a subset of 'mv'; see "examples/partial.go"
+newXml, err := newMap.Xml() // for example
+newJson, err := newMap.Json() // ditto
+
+
Usage
+
+The package is fairly well [self-documented with examples](http://godoc.org/github.com/clbanning/mxj).
+
+Also, the subdirectory "examples" contains a wide range of examples, several taken from golang-nuts discussions.
+
+
XML parsing conventions
+
+Using NewMapXml()
+
+ - Attributes are parsed to `map[string]interface{}` values by prefixing a hyphen, `-`,
+ to the attribute label. (Unless overridden by `PrependAttrWithHyphen(false)` or
+ `SetAttrPrefix()`.)
+ - If the element is a simple element and has attributes, the element value
+ is given the key `#text` for its `map[string]interface{}` representation. (See
+ the 'atomFeedString.xml' test data, below.)
+ - XML comments, directives, and process instructions are ignored.
+ - If CoerceKeysToLower() has been called, then the resultant keys will be lower case.
+
+Using NewMapXmlSeq()
+
+ - Attributes are parsed to `map["#attr"]map[]map[string]interface{}`values
+ where the `` value has "#text" and "#seq" keys - the "#text" key holds the
+ value for ``.
+ - All elements, except for the root, have a "#seq" key.
+ - Comments, directives, and process instructions are unmarshalled into the Map using the
+ keys "#comment", "#directive", and "#procinst", respectively. (See documentation for more
+ specifics.)
+ - Name space syntax is preserved:
+ - `something` parses to `map["ns:key"]interface{}{"something"}`
+ - `xmlns:ns="http://myns.com/ns"` parses to `map["xmlns:ns"]interface{}{"http://myns.com/ns"}`
+
+Both
+
+ - By default, "Nan", "Inf", and "-Inf" values are not cast to float64. If you want them
+ to be cast, set a flag to cast them using CastNanInf(true).
+
+
XML encoding conventions
+
+ - 'nil' `Map` values, which may represent 'null' JSON values, are encoded as ``.
+ NOTE: the operation is not symmetric as `` elements are decoded as `tag:""` `Map` values,
+ which, then, encode in JSON as `"tag":""` values.
+ - ALSO: there is no guarantee that the encoded XML doc will be the same as the decoded one. (Go
+ randomizes the walk through map[string]interface{} values.) If you plan to re-encode the
+ Map value to XML and want the same sequencing of elements look at NewMapXmlSeq() and
+ mv.XmlSeq() - these try to preserve the element sequencing but with added complexity when
+ working with the Map representation.
+
+
Running "go test"
+
+Because there are no guarantees on the sequence map elements are retrieved, the tests have been
+written for visual verification in most cases. One advantage is that you can easily use the
+output from running "go test" as examples of calling the various functions and methods.
+
+
Motivation
+
+I make extensive use of JSON for messaging and typically unmarshal the messages into
+`map[string]interface{}` values. This is easily done using `json.Unmarshal` from the
+standard Go libraries. Unfortunately, many legacy solutions use structured
+XML messages; in those environments the applications would have to be refactored to
+interoperate with my components.
+
+The better solution is to just provide an alternative HTTP handler that receives
+XML messages and parses it into a `map[string]interface{}` value and then reuse
+all the JSON-based code. The Go `xml.Unmarshal()` function does not provide the same
+option of unmarshaling XML messages into `map[string]interface{}` values. So I wrote
+a couple of small functions to fill this gap and released them as the x2j package.
+
+Over the next year and a half additional features were added, and the companion j2x
+package was released to address XML encoding of arbitrary JSON and `map[string]interface{}`
+values. As part of a refactoring of our production system and looking at how we had been
+using the x2j and j2x packages we found that we rarely performed direct XML-to-JSON or
+JSON-to_XML conversion and that working with the XML or JSON as `map[string]interface{}`
+values was the primary value. Thus, everything was refactored into the mxj package.
+
diff --git a/vendor/github.com/clbanning/mxj/remove.go b/vendor/github.com/clbanning/mxj/remove.go
new file mode 100644
index 0000000..8362ab1
--- /dev/null
+++ b/vendor/github.com/clbanning/mxj/remove.go
@@ -0,0 +1,37 @@
+package mxj
+
+import "strings"
+
+// Removes the path.
+func (mv Map) Remove(path string) error {
+ m := map[string]interface{}(mv)
+ return remove(m, path)
+}
+
+func remove(m interface{}, path string) error {
+ val, err := prevValueByPath(m, path)
+ if err != nil {
+ return err
+ }
+
+ lastKey := lastKey(path)
+ delete(val, lastKey)
+
+ return nil
+}
+
+// returns the last key of the path.
+// lastKey("a.b.c") would had returned "c"
+func lastKey(path string) string {
+ keys := strings.Split(path, ".")
+ key := keys[len(keys)-1]
+ return key
+}
+
+// returns the path without the last key
+// parentPath("a.b.c") whould had returned "a.b"
+func parentPath(path string) string {
+ keys := strings.Split(path, ".")
+ parentPath := strings.Join(keys[0:len(keys)-1], ".")
+ return parentPath
+}
diff --git a/vendor/github.com/clbanning/mxj/rename.go b/vendor/github.com/clbanning/mxj/rename.go
new file mode 100644
index 0000000..e95a963
--- /dev/null
+++ b/vendor/github.com/clbanning/mxj/rename.go
@@ -0,0 +1,54 @@
+package mxj
+
+import (
+ "errors"
+ "strings"
+)
+
+// RenameKey renames a key in a Map.
+// It works only for nested maps. It doesn't work for cases when it buried in a list.
+func (mv Map) RenameKey(path string, newName string) error {
+ if !mv.Exists(path) {
+ return errors.New("RenameKey: path not found: " + path)
+ }
+ if mv.Exists(parentPath(path) + "." + newName) {
+ return errors.New("RenameKey: key already exists: " + newName)
+ }
+
+ m := map[string]interface{}(mv)
+ return renameKey(m, path, newName)
+}
+
+func renameKey(m interface{}, path string, newName string) error {
+ val, err := prevValueByPath(m, path)
+ if err != nil {
+ return err
+ }
+
+ oldName := lastKey(path)
+ val[newName] = val[oldName]
+ delete(val, oldName)
+
+ return nil
+}
+
+// returns a value which contains a last key in the path
+// For example: prevValueByPath("a.b.c", {a{b{c: 3}}}) returns {c: 3}
+func prevValueByPath(m interface{}, path string) (map[string]interface{}, error) {
+ keys := strings.Split(path, ".")
+
+ switch mValue := m.(type) {
+ case map[string]interface{}:
+ for key, value := range mValue {
+ if key == keys[0] {
+ if len(keys) == 1 {
+ return mValue, nil
+ } else {
+ // keep looking for the full path to the key
+ return prevValueByPath(value, strings.Join(keys[1:], "."))
+ }
+ }
+ }
+ }
+ return nil, errors.New("prevValueByPath: didn't find path – " + path)
+}
diff --git a/vendor/github.com/clbanning/mxj/set.go b/vendor/github.com/clbanning/mxj/set.go
new file mode 100644
index 0000000..a297fc3
--- /dev/null
+++ b/vendor/github.com/clbanning/mxj/set.go
@@ -0,0 +1,26 @@
+package mxj
+
+import (
+ "strings"
+)
+
+// Sets the value for the path
+func (mv Map) SetValueForPath(value interface{}, path string) error {
+ pathAry := strings.Split(path, ".")
+ parentPathAry := pathAry[0 : len(pathAry)-1]
+ parentPath := strings.Join(parentPathAry, ".")
+
+ val, err := mv.ValueForPath(parentPath)
+ if err != nil {
+ return err
+ }
+ if val == nil {
+ return nil // we just ignore the request if there's no val
+ }
+
+ key := pathAry[len(pathAry)-1]
+ cVal := val.(map[string]interface{})
+ cVal[key] = value
+
+ return nil
+}
diff --git a/vendor/github.com/clbanning/mxj/setfieldsep.go b/vendor/github.com/clbanning/mxj/setfieldsep.go
new file mode 100644
index 0000000..b70715e
--- /dev/null
+++ b/vendor/github.com/clbanning/mxj/setfieldsep.go
@@ -0,0 +1,20 @@
+package mxj
+
+// Per: https://github.com/clbanning/mxj/issues/37#issuecomment-278651862
+var fieldSep string = ":"
+
+// SetFieldSeparator changes the default field separator, ":", for the
+// newVal argument in mv.UpdateValuesForPath and the optional 'subkey' arguments
+// in mv.ValuesForKey and mv.ValuesForPath.
+//
+// E.g., if the newVal value is "http://blah/blah", setting the field separator
+// to "|" will allow the newVal specification, "|http://blah/blah" to parse
+// properly. If called with no argument or an empty string value, the field
+// separator is set to the default, ":".
+func SetFieldSeparator(s ...string) {
+ if len(s) == 0 || s[0] == "" {
+ fieldSep = ":" // the default
+ return
+ }
+ fieldSep = s[0]
+}
diff --git a/vendor/github.com/clbanning/mxj/songtext.xml b/vendor/github.com/clbanning/mxj/songtext.xml
new file mode 100644
index 0000000..8c0f2be
--- /dev/null
+++ b/vendor/github.com/clbanning/mxj/songtext.xml
@@ -0,0 +1,29 @@
+
+ help me!
+
+
+
+ Henry was a renegade
+ Didn't like to play it safe
+ One component at a time
+ There's got to be a better way
+ Oh, people came from miles around
+ Searching for a steady job
+ Welcome to the Motor Town
+ Booming like an atom bomb
+
+
+ Oh, Henry was the end of the story
+ Then everything went wrong
+ And we'll return it to its former glory
+ But it just takes so long
+
+
+
+ It's going to take a long time
+ It's going to take it, but we'll make it one day
+ It's going to take a long time
+ It's going to take it, but we'll make it one day
+
+
+
diff --git a/vendor/github.com/clbanning/mxj/strict.go b/vendor/github.com/clbanning/mxj/strict.go
new file mode 100644
index 0000000..1e76956
--- /dev/null
+++ b/vendor/github.com/clbanning/mxj/strict.go
@@ -0,0 +1,30 @@
+// Copyright 2016 Charles Banning. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file
+
+// strict.go actually addresses setting xml.Decoder attribute
+// values. This'll let you parse non-standard XML.
+
+package mxj
+
+import (
+ "encoding/xml"
+)
+
+// CustomDecoder can be used to specify xml.Decoder attribute
+// values, e.g., Strict:false, to be used. By default CustomDecoder
+// is nil. If CustomeDecoder != nil, then mxj.XmlCharsetReader variable is
+// ignored and must be set as part of the CustomDecoder value, if needed.
+// Usage:
+// mxj.CustomDecoder = &xml.Decoder{Strict:false}
+var CustomDecoder *xml.Decoder
+
+// useCustomDecoder copy over public attributes from customDecoder
+func useCustomDecoder(d *xml.Decoder) {
+ d.Strict = CustomDecoder.Strict
+ d.AutoClose = CustomDecoder.AutoClose
+ d.Entity = CustomDecoder.Entity
+ d.CharsetReader = CustomDecoder.CharsetReader
+ d.DefaultSpace = CustomDecoder.DefaultSpace
+}
+
diff --git a/vendor/github.com/clbanning/mxj/struct.go b/vendor/github.com/clbanning/mxj/struct.go
new file mode 100644
index 0000000..9be636c
--- /dev/null
+++ b/vendor/github.com/clbanning/mxj/struct.go
@@ -0,0 +1,54 @@
+// Copyright 2012-2017 Charles Banning. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file
+
+package mxj
+
+import (
+ "encoding/json"
+ "errors"
+ "reflect"
+
+ // "github.com/fatih/structs"
+)
+
+// Create a new Map value from a structure. Error returned if argument is not a structure.
+// Only public structure fields are decoded in the Map value. See github.com/fatih/structs#Map
+// for handling of "structs" tags.
+
+// DEPRECATED - import github.com/fatih/structs and cast result of structs.Map to mxj.Map.
+// import "github.com/fatih/structs"
+// ...
+// sm, err := structs.Map()
+// if err != nil {
+// // handle error
+// }
+// m := mxj.Map(sm)
+// Alernatively uncomment the old source and import in struct.go.
+func NewMapStruct(structVal interface{}) (Map, error) {
+ return nil, errors.New("deprecated - see package documentation")
+ /*
+ if !structs.IsStruct(structVal) {
+ return nil, errors.New("NewMapStruct() error: argument is not type Struct")
+ }
+ return structs.Map(structVal), nil
+ */
+}
+
+// Marshal a map[string]interface{} into a structure referenced by 'structPtr'. Error returned
+// if argument is not a pointer or if json.Unmarshal returns an error.
+// json.Unmarshal structure encoding rules are followed to encode public structure fields.
+func (mv Map) Struct(structPtr interface{}) error {
+ // should check that we're getting a pointer.
+ if reflect.ValueOf(structPtr).Kind() != reflect.Ptr {
+ return errors.New("mv.Struct() error: argument is not type Ptr")
+ }
+
+ m := map[string]interface{}(mv)
+ j, err := json.Marshal(m)
+ if err != nil {
+ return err
+ }
+
+ return json.Unmarshal(j, structPtr)
+}
diff --git a/vendor/github.com/clbanning/mxj/updatevalues.go b/vendor/github.com/clbanning/mxj/updatevalues.go
new file mode 100644
index 0000000..46779f4
--- /dev/null
+++ b/vendor/github.com/clbanning/mxj/updatevalues.go
@@ -0,0 +1,256 @@
+// Copyright 2012-2014, 2017 Charles Banning. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file
+
+// updatevalues.go - modify a value based on path and possibly sub-keys
+// TODO(clb): handle simple elements with attributes and NewMapXmlSeq Map values.
+
+package mxj
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+)
+
+// Update value based on path and possible sub-key values.
+// A count of the number of values changed and any error are returned.
+// If the count == 0, then no path (and subkeys) matched.
+// 'newVal' can be a Map or map[string]interface{} value with a single 'key' that is the key to be modified
+// or a string value "key:value[:type]" where type is "bool" or "num" to cast the value.
+// 'path' is dot-notation list of keys to traverse; last key in path can be newVal key
+// NOTE: 'path' spec does not currently support indexed array references.
+// 'subkeys' are "key:value[:type]" entries that must match for path node
+// The subkey can be wildcarded - "key:*" - to require that it's there with some value.
+// If a subkey is preceeded with the '!' character, the key:value[:type] entry is treated as an
+// exclusion critera - e.g., "!author:William T. Gaddis".
+//
+// NOTES:
+// 1. Simple elements with attributes need a path terminated as ".#text" to modify the actual value.
+// 2. Values in Maps created using NewMapXmlSeq are map[string]interface{} values with a "#text" key.
+// 3. If values in 'newVal' or 'subkeys' args contain ":", use SetFieldSeparator to an unused symbol,
+// perhaps "|".
+func (mv Map) UpdateValuesForPath(newVal interface{}, path string, subkeys ...string) (int, error) {
+ m := map[string]interface{}(mv)
+
+ // extract the subkeys
+ var subKeyMap map[string]interface{}
+ if len(subkeys) > 0 {
+ var err error
+ subKeyMap, err = getSubKeyMap(subkeys...)
+ if err != nil {
+ return 0, err
+ }
+ }
+
+ // extract key and value from newVal
+ var key string
+ var val interface{}
+ switch newVal.(type) {
+ case map[string]interface{}, Map:
+ switch newVal.(type) { // "fallthrough is not permitted in type switch" (Spec)
+ case Map:
+ newVal = newVal.(Map).Old()
+ }
+ if len(newVal.(map[string]interface{})) != 1 {
+ return 0, fmt.Errorf("newVal map can only have len == 1 - %+v", newVal)
+ }
+ for key, val = range newVal.(map[string]interface{}) {
+ }
+ case string: // split it as a key:value pair
+ ss := strings.Split(newVal.(string), fieldSep)
+ n := len(ss)
+ if n < 2 || n > 3 {
+ return 0, fmt.Errorf("unknown newVal spec - %+v", newVal)
+ }
+ key = ss[0]
+ if n == 2 {
+ val = interface{}(ss[1])
+ } else if n == 3 {
+ switch ss[2] {
+ case "bool", "boolean":
+ nv, err := strconv.ParseBool(ss[1])
+ if err != nil {
+ return 0, fmt.Errorf("can't convert newVal to bool - %+v", newVal)
+ }
+ val = interface{}(nv)
+ case "num", "numeric", "float", "int":
+ nv, err := strconv.ParseFloat(ss[1], 64)
+ if err != nil {
+ return 0, fmt.Errorf("can't convert newVal to float64 - %+v", newVal)
+ }
+ val = interface{}(nv)
+ default:
+ return 0, fmt.Errorf("unknown type for newVal value - %+v", newVal)
+ }
+ }
+ default:
+ return 0, fmt.Errorf("invalid newVal type - %+v", newVal)
+ }
+
+ // parse path
+ keys := strings.Split(path, ".")
+
+ var count int
+ updateValuesForKeyPath(key, val, m, keys, subKeyMap, &count)
+
+ return count, nil
+}
+
+// navigate the path
+func updateValuesForKeyPath(key string, value interface{}, m interface{}, keys []string, subkeys map[string]interface{}, cnt *int) {
+ // ----- at end node: looking at possible node to get 'key' ----
+ if len(keys) == 1 {
+ updateValue(key, value, m, keys[0], subkeys, cnt)
+ return
+ }
+
+ // ----- here we are navigating the path thru the penultimate node --------
+ // key of interest is keys[0] - the next in the path
+ switch keys[0] {
+ case "*": // wildcard - scan all values
+ switch m.(type) {
+ case map[string]interface{}:
+ for _, v := range m.(map[string]interface{}) {
+ updateValuesForKeyPath(key, value, v, keys[1:], subkeys, cnt)
+ }
+ case []interface{}:
+ for _, v := range m.([]interface{}) {
+ switch v.(type) {
+ // flatten out a list of maps - keys are processed
+ case map[string]interface{}:
+ for _, vv := range v.(map[string]interface{}) {
+ updateValuesForKeyPath(key, value, vv, keys[1:], subkeys, cnt)
+ }
+ default:
+ updateValuesForKeyPath(key, value, v, keys[1:], subkeys, cnt)
+ }
+ }
+ }
+ default: // key - must be map[string]interface{}
+ switch m.(type) {
+ case map[string]interface{}:
+ if v, ok := m.(map[string]interface{})[keys[0]]; ok {
+ updateValuesForKeyPath(key, value, v, keys[1:], subkeys, cnt)
+ }
+ case []interface{}: // may be buried in list
+ for _, v := range m.([]interface{}) {
+ switch v.(type) {
+ case map[string]interface{}:
+ if vv, ok := v.(map[string]interface{})[keys[0]]; ok {
+ updateValuesForKeyPath(key, value, vv, keys[1:], subkeys, cnt)
+ }
+ }
+ }
+ }
+ }
+}
+
+// change value if key and subkeys are present
+func updateValue(key string, value interface{}, m interface{}, keys0 string, subkeys map[string]interface{}, cnt *int) {
+ // there are two possible options for the value of 'keys0': map[string]interface, []interface{}
+ // and 'key' is a key in the map or is a key in a map in a list.
+ switch m.(type) {
+ case map[string]interface{}: // gotta have the last key
+ if keys0 == "*" {
+ for k := range m.(map[string]interface{}) {
+ updateValue(key, value, m, k, subkeys, cnt)
+ }
+ return
+ }
+ endVal, _ := m.(map[string]interface{})[keys0]
+
+ // if newV key is the end of path, replace the value for path-end
+ // may be []interface{} - means replace just an entry w/ subkeys
+ // otherwise replace the keys0 value if subkeys are there
+ // NOTE: this will replace the subkeys, also
+ if key == keys0 {
+ switch endVal.(type) {
+ case map[string]interface{}:
+ if hasSubKeys(m, subkeys) {
+ (m.(map[string]interface{}))[keys0] = value
+ (*cnt)++
+ }
+ case []interface{}:
+ // without subkeys can't select list member to modify
+ // so key:value spec is it ...
+ if hasSubKeys(m, subkeys) {
+ (m.(map[string]interface{}))[keys0] = value
+ (*cnt)++
+ break
+ }
+ nv := make([]interface{}, 0)
+ var valmodified bool
+ for _, v := range endVal.([]interface{}) {
+ // check entry subkeys
+ if hasSubKeys(v, subkeys) {
+ // replace v with value
+ nv = append(nv, value)
+ valmodified = true
+ (*cnt)++
+ continue
+ }
+ nv = append(nv, v)
+ }
+ if valmodified {
+ (m.(map[string]interface{}))[keys0] = interface{}(nv)
+ }
+ default: // anything else is a strict replacement
+ if hasSubKeys(m, subkeys) {
+ (m.(map[string]interface{}))[keys0] = value
+ (*cnt)++
+ }
+ }
+ return
+ }
+
+ // so value is for an element of endVal
+ // if endVal is a map then 'key' must be there w/ subkeys
+ // if endVal is a list then 'key' must be in a list member w/ subkeys
+ switch endVal.(type) {
+ case map[string]interface{}:
+ if !hasSubKeys(endVal, subkeys) {
+ return
+ }
+ if _, ok := (endVal.(map[string]interface{}))[key]; ok {
+ (endVal.(map[string]interface{}))[key] = value
+ (*cnt)++
+ }
+ case []interface{}: // keys0 points to a list, check subkeys
+ for _, v := range endVal.([]interface{}) {
+ // got to be a map so we can replace value for 'key'
+ vv, vok := v.(map[string]interface{})
+ if !vok {
+ continue
+ }
+ if _, ok := vv[key]; !ok {
+ continue
+ }
+ if !hasSubKeys(vv, subkeys) {
+ continue
+ }
+ vv[key] = value
+ (*cnt)++
+ }
+ }
+ case []interface{}: // key may be in a list member
+ // don't need to handle keys0 == "*"; we're looking at everything, anyway.
+ for _, v := range m.([]interface{}) {
+ // only map values - we're looking for 'key'
+ mm, ok := v.(map[string]interface{})
+ if !ok {
+ continue
+ }
+ if _, ok := mm[key]; !ok {
+ continue
+ }
+ if !hasSubKeys(mm, subkeys) {
+ continue
+ }
+ mm[key] = value
+ (*cnt)++
+ }
+ }
+
+ // return
+}
diff --git a/vendor/github.com/clbanning/mxj/xml.go b/vendor/github.com/clbanning/mxj/xml.go
new file mode 100644
index 0000000..fac0f1d
--- /dev/null
+++ b/vendor/github.com/clbanning/mxj/xml.go
@@ -0,0 +1,1139 @@
+// Copyright 2012-2016 Charles Banning. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file
+
+// xml.go - basically the core of X2j for map[string]interface{} values.
+// NewMapXml, NewMapXmlReader, mv.Xml, mv.XmlWriter
+// see x2j and j2x for wrappers to provide end-to-end transformation of XML and JSON messages.
+
+package mxj
+
+import (
+ "bytes"
+ "encoding/json"
+ "encoding/xml"
+ "errors"
+ "fmt"
+ "io"
+ "reflect"
+ "sort"
+ "strconv"
+ "strings"
+ "time"
+)
+
+// ------------------- NewMapXml & NewMapXmlReader ... -------------------------
+
+// If XmlCharsetReader != nil, it will be used to decode the XML, if required.
+// Note: if CustomDecoder != nil, then XmlCharsetReader is ignored;
+// set the CustomDecoder attribute instead.
+// import (
+// charset "code.google.com/p/go-charset/charset"
+// github.com/clbanning/mxj
+// )
+// ...
+// mxj.XmlCharsetReader = charset.NewReader
+// m, merr := mxj.NewMapXml(xmlValue)
+var XmlCharsetReader func(charset string, input io.Reader) (io.Reader, error)
+
+// NewMapXml - convert a XML doc into a Map
+// (This is analogous to unmarshalling a JSON string to map[string]interface{} using json.Unmarshal().)
+// If the optional argument 'cast' is 'true', then values will be converted to boolean or float64 if possible.
+//
+// Converting XML to JSON is a simple as:
+// ...
+// mapVal, merr := mxj.NewMapXml(xmlVal)
+// if merr != nil {
+// // handle error
+// }
+// jsonVal, jerr := mapVal.Json()
+// if jerr != nil {
+// // handle error
+// }
+//
+// NOTES:
+// 1. The 'xmlVal' will be parsed looking for an xml.StartElement, so BOM and other
+// extraneous xml.CharData will be ignored unless io.EOF is reached first.
+// 2. If CoerceKeysToLower() has been called, then all key values will be lower case.
+// 3. If CoerceKeysToSnakeCase() has been called, then all key values will be converted to snake case.
+func NewMapXml(xmlVal []byte, cast ...bool) (Map, error) {
+ var r bool
+ if len(cast) == 1 {
+ r = cast[0]
+ }
+ return xmlToMap(xmlVal, r)
+}
+
+// Get next XML doc from an io.Reader as a Map value. Returns Map value.
+// NOTES:
+// 1. The 'xmlReader' will be parsed looking for an xml.StartElement, so BOM and other
+// extraneous xml.CharData will be ignored unless io.EOF is reached first.
+// 2. If CoerceKeysToLower() has been called, then all key values will be lower case.
+// 3. If CoerceKeysToSnakeCase() has been called, then all key values will be converted to snake case.
+func NewMapXmlReader(xmlReader io.Reader, cast ...bool) (Map, error) {
+ var r bool
+ if len(cast) == 1 {
+ r = cast[0]
+ }
+
+ // We need to put an *os.File reader in a ByteReader or the xml.NewDecoder
+ // will wrap it in a bufio.Reader and seek on the file beyond where the
+ // xml.Decoder parses!
+ if _, ok := xmlReader.(io.ByteReader); !ok {
+ xmlReader = myByteReader(xmlReader) // see code at EOF
+ }
+
+ // build the map
+ return xmlReaderToMap(xmlReader, r)
+}
+
+// Get next XML doc from an io.Reader as a Map value. Returns Map value and slice with the raw XML.
+// NOTES:
+// 1. Due to the implementation of xml.Decoder, the raw XML off the reader is buffered to []byte
+// using a ByteReader. If the io.Reader is an os.File, there may be significant performance impact.
+// See the examples - getmetrics1.go through getmetrics4.go - for comparative use cases on a large
+// data set. If the io.Reader is wrapping a []byte value in-memory, however, such as http.Request.Body
+// you CAN use it to efficiently unmarshal a XML doc and retrieve the raw XML in a single call.
+// 2. The 'raw' return value may be larger than the XML text value.
+// 3. The 'xmlReader' will be parsed looking for an xml.StartElement, so BOM and other
+// extraneous xml.CharData will be ignored unless io.EOF is reached first.
+// 4. If CoerceKeysToLower() has been called, then all key values will be lower case.
+// 5. If CoerceKeysToSnakeCase() has been called, then all key values will be converted to snake case.
+func NewMapXmlReaderRaw(xmlReader io.Reader, cast ...bool) (Map, []byte, error) {
+ var r bool
+ if len(cast) == 1 {
+ r = cast[0]
+ }
+ // create TeeReader so we can retrieve raw XML
+ buf := make([]byte, 0)
+ wb := bytes.NewBuffer(buf)
+ trdr := myTeeReader(xmlReader, wb) // see code at EOF
+
+ m, err := xmlReaderToMap(trdr, r)
+
+ // retrieve the raw XML that was decoded
+ b := wb.Bytes()
+
+ if err != nil {
+ return nil, b, err
+ }
+
+ return m, b, nil
+}
+
+// xmlReaderToMap() - parse a XML io.Reader to a map[string]interface{} value
+func xmlReaderToMap(rdr io.Reader, r bool) (map[string]interface{}, error) {
+ // parse the Reader
+ p := xml.NewDecoder(rdr)
+ if CustomDecoder != nil {
+ useCustomDecoder(p)
+ } else {
+ p.CharsetReader = XmlCharsetReader
+ }
+ return xmlToMapParser("", nil, p, r)
+}
+
+// xmlToMap - convert a XML doc into map[string]interface{} value
+func xmlToMap(doc []byte, r bool) (map[string]interface{}, error) {
+ b := bytes.NewReader(doc)
+ p := xml.NewDecoder(b)
+ if CustomDecoder != nil {
+ useCustomDecoder(p)
+ } else {
+ p.CharsetReader = XmlCharsetReader
+ }
+ return xmlToMapParser("", nil, p, r)
+}
+
+// ===================================== where the work happens =============================
+
+// PrependAttrWithHyphen. Prepend attribute tags with a hyphen.
+// Default is 'true'. (Not applicable to NewMapXmlSeq(), mv.XmlSeq(), etc.)
+// Note:
+// If 'false', unmarshaling and marshaling is not symmetric. Attributes will be
+// marshal'd as attr and may be part of a list.
+func PrependAttrWithHyphen(v bool) {
+ if v {
+ attrPrefix = "-"
+ lenAttrPrefix = len(attrPrefix)
+ return
+ }
+ attrPrefix = ""
+ lenAttrPrefix = len(attrPrefix)
+}
+
+// Include sequence id with inner tags. - per Sean Murphy, murphysean84@gmail.com.
+var includeTagSeqNum bool
+
+// IncludeTagSeqNum - include a "_seq":N key:value pair with each inner tag, denoting
+// its position when parsed. This is of limited usefulness, since list values cannot
+// be tagged with "_seq" without changing their depth in the Map.
+// So THIS SHOULD BE USED WITH CAUTION - see the test cases. Here's a sample of what
+// you get.
+/*
+
+
+
+
+ hello
+
+
+ parses as:
+
+ {
+ Obj:{
+ "-c":"la",
+ "-h":"da",
+ "-x":"dee",
+ "intObj":[
+ {
+ "-id"="3",
+ "_seq":"0" // if mxj.Cast is passed, then: "_seq":0
+ },
+ {
+ "-id"="2",
+ "_seq":"2"
+ }],
+ "intObj1":{
+ "-id":"1",
+ "_seq":"1"
+ },
+ "StrObj":{
+ "#text":"hello", // simple element value gets "#text" tag
+ "_seq":"3"
+ }
+ }
+ }
+*/
+func IncludeTagSeqNum(b bool) {
+ includeTagSeqNum = b
+}
+
+// all keys will be "lower case"
+var lowerCase bool
+
+// Coerce all tag values to keys in lower case. This is useful if you've got sources with variable
+// tag capitalization, and you want to use m.ValuesForKeys(), etc., with the key or path spec
+// in lower case.
+// CoerceKeysToLower() will toggle the coercion flag true|false - on|off
+// CoerceKeysToLower(true|false) will set the coercion flag on|off
+//
+// NOTE: only recognized by NewMapXml, NewMapXmlReader, and NewMapXmlReaderRaw functions as well as
+// the associated HandleXmlReader and HandleXmlReaderRaw.
+func CoerceKeysToLower(b ...bool) {
+ if len(b) == 0 {
+ lowerCase = !lowerCase
+ } else if len(b) == 1 {
+ lowerCase = b[0]
+ }
+}
+
+// 25jun16: Allow user to specify the "prefix" character for XML attribute key labels.
+// We do this by replacing '`' constant with attrPrefix var, replacing useHyphen with attrPrefix = "",
+// and adding a SetAttrPrefix(s string) function.
+
+var attrPrefix string = `-` // the default
+var lenAttrPrefix int = 1 // the default
+
+// SetAttrPrefix changes the default, "-", to the specified value, s.
+// SetAttrPrefix("") is the same as PrependAttrWithHyphen(false).
+// (Not applicable for NewMapXmlSeq(), mv.XmlSeq(), etc.)
+func SetAttrPrefix(s string) {
+ attrPrefix = s
+ lenAttrPrefix = len(attrPrefix)
+}
+
+// 18jan17: Allows user to specify if the map keys should be in snake case instead
+// of the default hyphenated notation.
+var snakeCaseKeys bool
+
+// CoerceKeysToSnakeCase changes the default, false, to the specified value, b.
+// Note: the attribute prefix will be a hyphen, '-', or what ever string value has
+// been specified using SetAttrPrefix.
+func CoerceKeysToSnakeCase(b ...bool) {
+ if len(b) == 0 {
+ snakeCaseKeys = !snakeCaseKeys
+ } else if len(b) == 1 {
+ snakeCaseKeys = b[0]
+ }
+}
+
+// 05feb17: support processing XMPP streams (issue #36)
+var handleXMPPStreamTag bool
+
+// HandleXMPPStreamTag causes decoder to parse XMPP elements.
+// If called with no argument, XMPP stream element handling is toggled on/off.
+// (See xmppStream_test.go for example.)
+// If called with NewMapXml, NewMapXmlReader, New MapXmlReaderRaw the "stream"
+// element will be returned as:
+// map["stream"]interface{}{map[-]interface{}}.
+// If called with NewMapSeq, NewMapSeqReader, NewMapSeqReaderRaw the "stream"
+// element will be returned as:
+// map["stream:stream"]interface{}{map["#attr"]interface{}{map[string]interface{}}}
+// where the "#attr" values have "#text" and "#seq" keys. (See NewMapXmlSeq.)
+func HandleXMPPStreamTag(b ...bool) {
+ if len(b) == 0 {
+ handleXMPPStreamTag = !handleXMPPStreamTag
+ } else if len(b) == 1 {
+ handleXMPPStreamTag = b[0]
+ }
+}
+
+// 21jan18 - decode all values as map["#text":value] (issue #56)
+var decodeSimpleValuesAsMap bool
+
+// DecodeSimpleValuesAsMap forces all values to be decoded as map["#text":].
+// If called with no argument, the decoding is toggled on/off.
+//
+// By default the NewMapXml functions decode simple values without attributes as
+// map[:]. This function causes simple values without attributes to be
+// decoded the same as simple values with attributes - map[:map["#text":]].
+func DecodeSimpleValuesAsMap(b ...bool) {
+ if len(b) == 0 {
+ decodeSimpleValuesAsMap = !decodeSimpleValuesAsMap
+ } else if len(b) == 1 {
+ decodeSimpleValuesAsMap = b[0]
+ }
+}
+
+// xmlToMapParser (2015.11.12) - load a 'clean' XML doc into a map[string]interface{} directly.
+// A refactoring of xmlToTreeParser(), markDuplicate() and treeToMap() - here, all-in-one.
+// We've removed the intermediate *node tree with the allocation and subsequent rescanning.
+func xmlToMapParser(skey string, a []xml.Attr, p *xml.Decoder, r bool) (map[string]interface{}, error) {
+ if lowerCase {
+ skey = strings.ToLower(skey)
+ }
+ if snakeCaseKeys {
+ skey = strings.Replace(skey, "-", "_", -1)
+ }
+
+ // NOTE: all attributes and sub-elements parsed into 'na', 'na' is returned as value for 'skey' in 'n'.
+ // Unless 'skey' is a simple element w/o attributes, in which case the xml.CharData value is the value.
+ var n, na map[string]interface{}
+ var seq int // for includeTagSeqNum
+
+ // Allocate maps and load attributes, if any.
+ // NOTE: on entry from NewMapXml(), etc., skey=="", and we fall through
+ // to get StartElement then recurse with skey==xml.StartElement.Name.Local
+ // where we begin allocating map[string]interface{} values 'n' and 'na'.
+ if skey != "" {
+ n = make(map[string]interface{}) // old n
+ na = make(map[string]interface{}) // old n.nodes
+ if len(a) > 0 {
+ for _, v := range a {
+ if snakeCaseKeys {
+ v.Name.Local = strings.Replace(v.Name.Local, "-", "_", -1)
+ }
+ var key string
+ key = attrPrefix + v.Name.Local
+ if lowerCase {
+ key = strings.ToLower(key)
+ }
+ na[key] = cast(v.Value, r)
+ }
+ }
+ }
+ // Return XMPP message.
+ if handleXMPPStreamTag && skey == "stream" {
+ n[skey] = na
+ return n, nil
+ }
+
+ for {
+ t, err := p.Token()
+ if err != nil {
+ if err != io.EOF {
+ return nil, errors.New("xml.Decoder.Token() - " + err.Error())
+ }
+ return nil, err
+ }
+ switch t.(type) {
+ case xml.StartElement:
+ tt := t.(xml.StartElement)
+
+ // First call to xmlToMapParser() doesn't pass xml.StartElement - the map key.
+ // So when the loop is first entered, the first token is the root tag along
+ // with any attributes, which we process here.
+ //
+ // Subsequent calls to xmlToMapParser() will pass in tag+attributes for
+ // processing before getting the next token which is the element value,
+ // which is done above.
+ if skey == "" {
+ return xmlToMapParser(tt.Name.Local, tt.Attr, p, r)
+ }
+
+ // If not initializing the map, parse the element.
+ // len(nn) == 1, necessarily - it is just an 'n'.
+ nn, err := xmlToMapParser(tt.Name.Local, tt.Attr, p, r)
+ if err != nil {
+ return nil, err
+ }
+
+ // The nn map[string]interface{} value is a na[nn_key] value.
+ // We need to see if nn_key already exists - means we're parsing a list.
+ // This may require converting na[nn_key] value into []interface{} type.
+ // First, extract the key:val for the map - it's a singleton.
+ // Note:
+ // * if CoerceKeysToLower() called, then key will be lower case.
+ // * if CoerceKeysToSnakeCase() called, then key will be converted to snake case.
+ var key string
+ var val interface{}
+ for key, val = range nn {
+ break
+ }
+
+ // IncludeTagSeqNum requests that the element be augmented with a "_seq" sub-element.
+ // In theory, we don't need this if len(na) == 1. But, we don't know what might
+ // come next - we're only parsing forward. So if you ask for 'includeTagSeqNum' you
+ // get it on every element. (Personally, I never liked this, but I added it on request
+ // and did get a $50 Amazon gift card in return - now we support it for backwards compatibility!)
+ if includeTagSeqNum {
+ switch val.(type) {
+ case []interface{}:
+ // noop - There's no clean way to handle this w/o changing message structure.
+ case map[string]interface{}:
+ val.(map[string]interface{})["_seq"] = seq // will overwrite an "_seq" XML tag
+ seq++
+ case interface{}: // a non-nil simple element: string, float64, bool
+ v := map[string]interface{}{"#text": val}
+ v["_seq"] = seq
+ seq++
+ val = v
+ }
+ }
+
+ // 'na' holding sub-elements of n.
+ // See if 'key' already exists.
+ // If 'key' exists, then this is a list, if not just add key:val to na.
+ if v, ok := na[key]; ok {
+ var a []interface{}
+ switch v.(type) {
+ case []interface{}:
+ a = v.([]interface{})
+ default: // anything else - note: v.(type) != nil
+ a = []interface{}{v}
+ }
+ a = append(a, val)
+ na[key] = a
+ } else {
+ na[key] = val // save it as a singleton
+ }
+ case xml.EndElement:
+ // len(n) > 0 if this is a simple element w/o xml.Attrs - see xml.CharData case.
+ if len(n) == 0 {
+ // If len(na)==0 we have an empty element == "";
+ // it has no xml.Attr nor xml.CharData.
+ // Note: in original node-tree parser, val defaulted to "";
+ // so we always had the default if len(node.nodes) == 0.
+ if len(na) > 0 {
+ n[skey] = na
+ } else {
+ n[skey] = "" // empty element
+ }
+ }
+ return n, nil
+ case xml.CharData:
+ // clean up possible noise
+ tt := strings.Trim(string(t.(xml.CharData)), "\t\r\b\n ")
+ if len(tt) > 0 {
+ if len(na) > 0 || decodeSimpleValuesAsMap {
+ na["#text"] = cast(tt, r)
+ } else if skey != "" {
+ n[skey] = cast(tt, r)
+ } else {
+ // per Adrian (http://www.adrianlungu.com/) catch stray text
+ // in decoder stream -
+ // https://github.com/clbanning/mxj/pull/14#issuecomment-182816374
+ // NOTE: CharSetReader must be set to non-UTF-8 CharSet or you'll get
+ // a p.Token() decoding error when the BOM is UTF-16 or UTF-32.
+ continue
+ }
+ }
+ default:
+ // noop
+ }
+ }
+}
+
+var castNanInf bool
+
+// Cast "Nan", "Inf", "-Inf" XML values to 'float64'.
+// By default, these values will be decoded as 'string'.
+func CastNanInf(b bool) {
+ castNanInf = b
+}
+
+// cast - try to cast string values to bool or float64
+func cast(s string, r bool) interface{} {
+ if r {
+ // handle nan and inf
+ if !castNanInf {
+ switch strings.ToLower(s) {
+ case "nan", "inf", "-inf":
+ return s
+ }
+ }
+
+ // handle numeric strings ahead of boolean
+ if f, err := strconv.ParseFloat(s, 64); err == nil {
+ return f
+ }
+ // ParseBool treats "1"==true & "0"==false, we've already scanned those
+ // values as float64. See if value has 't' or 'f' as initial screen to
+ // minimize calls to ParseBool; also, see if len(s) < 6.
+ if len(s) > 0 && len(s) < 6 {
+ switch s[:1] {
+ case "t", "T", "f", "F":
+ if b, err := strconv.ParseBool(s); err == nil {
+ return b
+ }
+ }
+ }
+ }
+ return s
+}
+
+// ------------------ END: NewMapXml & NewMapXmlReader -------------------------
+
+// ------------------ mv.Xml & mv.XmlWriter - from j2x ------------------------
+
+const (
+ DefaultRootTag = "doc"
+)
+
+var useGoXmlEmptyElemSyntax bool
+
+// XmlGoEmptyElemSyntax() - rather than .
+// Go's encoding/xml package marshals empty XML elements as . By default this package
+// encodes empty elements as . If you're marshaling Map values that include structures
+// (which are passed to xml.Marshal for encoding), this will let you conform to the standard package.
+func XmlGoEmptyElemSyntax() {
+ useGoXmlEmptyElemSyntax = true
+}
+
+// XmlDefaultEmptyElemSyntax() - rather than .
+// Return XML encoding for empty elements to the default package setting.
+// Reverses effect of XmlGoEmptyElemSyntax().
+func XmlDefaultEmptyElemSyntax() {
+ useGoXmlEmptyElemSyntax = false
+}
+
+// Encode a Map as XML. The companion of NewMapXml().
+// The following rules apply.
+// - The key label "#text" is treated as the value for a simple element with attributes.
+// - Map keys that begin with a hyphen, '-', are interpreted as attributes.
+// It is an error if the attribute doesn't have a []byte, string, number, or boolean value.
+// - Map value type encoding:
+// > string, bool, float64, int, int32, int64, float32: per "%v" formating
+// > []bool, []uint8: by casting to string
+// > structures, etc.: handed to xml.Marshal() - if there is an error, the element
+// value is "UNKNOWN"
+// - Elements with only attribute values or are null are terminated using "/>".
+// - If len(mv) == 1 and no rootTag is provided, then the map key is used as the root tag, possible.
+// Thus, `{ "key":"value" }` encodes as "value".
+// - To encode empty elements in a syntax consistent with encoding/xml call UseGoXmlEmptyElementSyntax().
+// The attributes tag=value pairs are alphabetized by "tag". Also, when encoding map[string]interface{} values -
+// complex elements, etc. - the key:value pairs are alphabetized by key so the resulting tags will appear sorted.
+func (mv Map) Xml(rootTag ...string) ([]byte, error) {
+ m := map[string]interface{}(mv)
+ var err error
+ s := new(string)
+ p := new(pretty) // just a stub
+
+ if len(m) == 1 && len(rootTag) == 0 {
+ for key, value := range m {
+ // if it an array, see if all values are map[string]interface{}
+ // we force a new root tag if we'll end up with no key:value in the list
+ // so: key:[string_val, bool:true] --> string_valtrue
+ switch value.(type) {
+ case []interface{}:
+ for _, v := range value.([]interface{}) {
+ switch v.(type) {
+ case map[string]interface{}: // noop
+ default: // anything else
+ err = mapToXmlIndent(false, s, DefaultRootTag, m, p)
+ goto done
+ }
+ }
+ }
+ err = mapToXmlIndent(false, s, key, value, p)
+ }
+ } else if len(rootTag) == 1 {
+ err = mapToXmlIndent(false, s, rootTag[0], m, p)
+ } else {
+ err = mapToXmlIndent(false, s, DefaultRootTag, m, p)
+ }
+done:
+ return []byte(*s), err
+}
+
+// The following implementation is provided only for symmetry with NewMapXmlReader[Raw]
+// The names will also provide a key for the number of return arguments.
+
+// Writes the Map as XML on the Writer.
+// See Xml() for encoding rules.
+func (mv Map) XmlWriter(xmlWriter io.Writer, rootTag ...string) error {
+ x, err := mv.Xml(rootTag...)
+ if err != nil {
+ return err
+ }
+
+ _, err = xmlWriter.Write(x)
+ return err
+}
+
+// Writes the Map as XML on the Writer. []byte is the raw XML that was written.
+// See Xml() for encoding rules.
+func (mv Map) XmlWriterRaw(xmlWriter io.Writer, rootTag ...string) ([]byte, error) {
+ x, err := mv.Xml(rootTag...)
+ if err != nil {
+ return x, err
+ }
+
+ _, err = xmlWriter.Write(x)
+ return x, err
+}
+
+// Writes the Map as pretty XML on the Writer.
+// See Xml() for encoding rules.
+func (mv Map) XmlIndentWriter(xmlWriter io.Writer, prefix, indent string, rootTag ...string) error {
+ x, err := mv.XmlIndent(prefix, indent, rootTag...)
+ if err != nil {
+ return err
+ }
+
+ _, err = xmlWriter.Write(x)
+ return err
+}
+
+// Writes the Map as pretty XML on the Writer. []byte is the raw XML that was written.
+// See Xml() for encoding rules.
+func (mv Map) XmlIndentWriterRaw(xmlWriter io.Writer, prefix, indent string, rootTag ...string) ([]byte, error) {
+ x, err := mv.XmlIndent(prefix, indent, rootTag...)
+ if err != nil {
+ return x, err
+ }
+
+ _, err = xmlWriter.Write(x)
+ return x, err
+}
+
+// -------------------- END: mv.Xml & mv.XmlWriter -------------------------------
+
+// -------------- Handle XML stream by processing Map value --------------------
+
+// Default poll delay to keep Handler from spinning on an open stream
+// like sitting on os.Stdin waiting for imput.
+var xhandlerPollInterval = time.Millisecond
+
+// Bulk process XML using handlers that process a Map value.
+// 'rdr' is an io.Reader for XML (stream)
+// 'mapHandler' is the Map processor. Return of 'false' stops io.Reader processing.
+// 'errHandler' is the error processor. Return of 'false' stops io.Reader processing and returns the error.
+// Note: mapHandler() and errHandler() calls are blocking, so reading and processing of messages is serialized.
+// This means that you can stop reading the file on error or after processing a particular message.
+// To have reading and handling run concurrently, pass argument to a go routine in handler and return 'true'.
+func HandleXmlReader(xmlReader io.Reader, mapHandler func(Map) bool, errHandler func(error) bool) error {
+ var n int
+ for {
+ m, merr := NewMapXmlReader(xmlReader)
+ n++
+
+ // handle error condition with errhandler
+ if merr != nil && merr != io.EOF {
+ merr = fmt.Errorf("[xmlReader: %d] %s", n, merr.Error())
+ if ok := errHandler(merr); !ok {
+ // caused reader termination
+ return merr
+ }
+ continue
+ }
+
+ // pass to maphandler
+ if len(m) != 0 {
+ if ok := mapHandler(m); !ok {
+ break
+ }
+ } else if merr != io.EOF {
+ time.Sleep(xhandlerPollInterval)
+ }
+
+ if merr == io.EOF {
+ break
+ }
+ }
+ return nil
+}
+
+// Bulk process XML using handlers that process a Map value and the raw XML.
+// 'rdr' is an io.Reader for XML (stream)
+// 'mapHandler' is the Map and raw XML - []byte - processor. Return of 'false' stops io.Reader processing.
+// 'errHandler' is the error and raw XML processor. Return of 'false' stops io.Reader processing and returns the error.
+// Note: mapHandler() and errHandler() calls are blocking, so reading and processing of messages is serialized.
+// This means that you can stop reading the file on error or after processing a particular message.
+// To have reading and handling run concurrently, pass argument(s) to a go routine in handler and return 'true'.
+// See NewMapXmlReaderRaw for comment on performance associated with retrieving raw XML from a Reader.
+func HandleXmlReaderRaw(xmlReader io.Reader, mapHandler func(Map, []byte) bool, errHandler func(error, []byte) bool) error {
+ var n int
+ for {
+ m, raw, merr := NewMapXmlReaderRaw(xmlReader)
+ n++
+
+ // handle error condition with errhandler
+ if merr != nil && merr != io.EOF {
+ merr = fmt.Errorf("[xmlReader: %d] %s", n, merr.Error())
+ if ok := errHandler(merr, raw); !ok {
+ // caused reader termination
+ return merr
+ }
+ continue
+ }
+
+ // pass to maphandler
+ if len(m) != 0 {
+ if ok := mapHandler(m, raw); !ok {
+ break
+ }
+ } else if merr != io.EOF {
+ time.Sleep(xhandlerPollInterval)
+ }
+
+ if merr == io.EOF {
+ break
+ }
+ }
+ return nil
+}
+
+// ----------------- END: Handle XML stream by processing Map value --------------
+
+// -------- a hack of io.TeeReader ... need one that's an io.ByteReader for xml.NewDecoder() ----------
+
+// This is a clone of io.TeeReader with the additional method t.ReadByte().
+// Thus, this TeeReader is also an io.ByteReader.
+// This is necessary because xml.NewDecoder uses a ByteReader not a Reader. It appears to have been written
+// with bufio.Reader or bytes.Reader in mind ... not a generic io.Reader, which doesn't have to have ReadByte()..
+// If NewDecoder is passed a Reader that does not satisfy ByteReader() it wraps the Reader with
+// bufio.NewReader and uses ReadByte rather than Read that runs the TeeReader pipe logic.
+
+type teeReader struct {
+ r io.Reader
+ w io.Writer
+ b []byte
+}
+
+func myTeeReader(r io.Reader, w io.Writer) io.Reader {
+ b := make([]byte, 1)
+ return &teeReader{r, w, b}
+}
+
+// need for io.Reader - but we don't use it ...
+func (t *teeReader) Read(p []byte) (int, error) {
+ return 0, nil
+}
+
+func (t *teeReader) ReadByte() (byte, error) {
+ n, err := t.r.Read(t.b)
+ if n > 0 {
+ if _, err := t.w.Write(t.b[:1]); err != nil {
+ return t.b[0], err
+ }
+ }
+ return t.b[0], err
+}
+
+// For use with NewMapXmlReader & NewMapXmlSeqReader.
+type byteReader struct {
+ r io.Reader
+ b []byte
+}
+
+func myByteReader(r io.Reader) io.Reader {
+ b := make([]byte, 1)
+ return &byteReader{r, b}
+}
+
+// Need for io.Reader interface ...
+// Needed if reading a malformed http.Request.Body - issue #38.
+func (b *byteReader) Read(p []byte) (int, error) {
+ return b.r.Read(p)
+}
+
+func (b *byteReader) ReadByte() (byte, error) {
+ _, err := b.r.Read(b.b)
+ if len(b.b) > 0 {
+ return b.b[0], err
+ }
+ var c byte
+ return c, err
+}
+
+// ----------------------- END: io.TeeReader hack -----------------------------------
+
+// ---------------------- XmlIndent - from j2x package ----------------------------
+
+// Encode a map[string]interface{} as a pretty XML string.
+// See Xml for encoding rules.
+func (mv Map) XmlIndent(prefix, indent string, rootTag ...string) ([]byte, error) {
+ m := map[string]interface{}(mv)
+
+ var err error
+ s := new(string)
+ p := new(pretty)
+ p.indent = indent
+ p.padding = prefix
+
+ if len(m) == 1 && len(rootTag) == 0 {
+ // this can extract the key for the single map element
+ // use it if it isn't a key for a list
+ for key, value := range m {
+ if _, ok := value.([]interface{}); ok {
+ err = mapToXmlIndent(true, s, DefaultRootTag, m, p)
+ } else {
+ err = mapToXmlIndent(true, s, key, value, p)
+ }
+ }
+ } else if len(rootTag) == 1 {
+ err = mapToXmlIndent(true, s, rootTag[0], m, p)
+ } else {
+ err = mapToXmlIndent(true, s, DefaultRootTag, m, p)
+ }
+ return []byte(*s), err
+}
+
+type pretty struct {
+ indent string
+ cnt int
+ padding string
+ mapDepth int
+ start int
+}
+
+func (p *pretty) Indent() {
+ p.padding += p.indent
+ p.cnt++
+}
+
+func (p *pretty) Outdent() {
+ if p.cnt > 0 {
+ p.padding = p.padding[:len(p.padding)-len(p.indent)]
+ p.cnt--
+ }
+}
+
+// where the work actually happens
+// returns an error if an attribute is not atomic
+func mapToXmlIndent(doIndent bool, s *string, key string, value interface{}, pp *pretty) error {
+ var endTag bool
+ var isSimple bool
+ var elen int
+ p := &pretty{pp.indent, pp.cnt, pp.padding, pp.mapDepth, pp.start}
+
+ // per issue #48, 18apr18 - try and coerce maps to map[string]interface{}
+ // Don't need for mapToXmlSeqIndent, since maps there are decoded by NewMapXmlSeq().
+ if reflect.ValueOf(value).Kind() == reflect.Map {
+ switch value.(type) {
+ case map[string]interface{}:
+ default:
+ val := make(map[string]interface{})
+ vv := reflect.ValueOf(value)
+ keys := vv.MapKeys()
+ for _, k := range keys {
+ val[fmt.Sprint(k)] = vv.MapIndex(k).Interface()
+ }
+ value = val
+ }
+ }
+
+ switch value.(type) {
+ // special handling of []interface{} values when len(value) == 0
+ case map[string]interface{}, []byte, string, float64, bool, int, int32, int64, float32, json.Number:
+ if doIndent {
+ *s += p.padding
+ }
+ *s += `<` + key
+ }
+ switch value.(type) {
+ case map[string]interface{}:
+ vv := value.(map[string]interface{})
+ lenvv := len(vv)
+ // scan out attributes - attribute keys have prepended attrPrefix
+ attrlist := make([][2]string, len(vv))
+ var n int
+ var ss string
+ for k, v := range vv {
+ if lenAttrPrefix > 0 && lenAttrPrefix < len(k) && k[:lenAttrPrefix] == attrPrefix {
+ switch v.(type) {
+ case string:
+ if xmlEscapeChars {
+ ss = escapeChars(v.(string))
+ } else {
+ ss = v.(string)
+ }
+ attrlist[n][0] = k[lenAttrPrefix:]
+ attrlist[n][1] = ss
+ case float64, bool, int, int32, int64, float32, json.Number:
+ attrlist[n][0] = k[lenAttrPrefix:]
+ attrlist[n][1] = fmt.Sprintf("%v", v)
+ case []byte:
+ if xmlEscapeChars {
+ ss = escapeChars(string(v.([]byte)))
+ } else {
+ ss = string(v.([]byte))
+ }
+ attrlist[n][0] = k[lenAttrPrefix:]
+ attrlist[n][1] = ss
+ default:
+ return fmt.Errorf("invalid attribute value for: %s:<%T>", k, v)
+ }
+ n++
+ }
+ }
+ if n > 0 {
+ attrlist = attrlist[:n]
+ sort.Sort(attrList(attrlist))
+ for _, v := range attrlist {
+ *s += ` ` + v[0] + `="` + v[1] + `"`
+ }
+ }
+ // only attributes?
+ if n == lenvv {
+ if useGoXmlEmptyElemSyntax {
+ *s += `` + key + ">"
+ } else {
+ *s += `/>`
+ }
+ break
+ }
+
+ // simple element? Note: '#text" is an invalid XML tag.
+ if v, ok := vv["#text"]; ok && n+1 == lenvv {
+ switch v.(type) {
+ case string:
+ if xmlEscapeChars {
+ v = escapeChars(v.(string))
+ } else {
+ v = v.(string)
+ }
+ case []byte:
+ if xmlEscapeChars {
+ v = escapeChars(string(v.([]byte)))
+ }
+ }
+ *s += ">" + fmt.Sprintf("%v", v)
+ endTag = true
+ elen = 1
+ isSimple = true
+ break
+ } else if ok {
+ // Handle edge case where simple element with attributes
+ // is unmarshal'd using NewMapXml() where attribute prefix
+ // has been set to "".
+ // TODO(clb): should probably scan all keys for invalid chars.
+ return fmt.Errorf("invalid attribute key label: #text - due to attributes not being prefixed")
+ }
+
+ // close tag with possible attributes
+ *s += ">"
+ if doIndent {
+ *s += "\n"
+ }
+ // something more complex
+ p.mapDepth++
+ // extract the map k:v pairs and sort on key
+ elemlist := make([][2]interface{}, len(vv))
+ n = 0
+ for k, v := range vv {
+ if lenAttrPrefix > 0 && lenAttrPrefix < len(k) && k[:lenAttrPrefix] == attrPrefix {
+ continue
+ }
+ elemlist[n][0] = k
+ elemlist[n][1] = v
+ n++
+ }
+ elemlist = elemlist[:n]
+ sort.Sort(elemList(elemlist))
+ var i int
+ for _, v := range elemlist {
+ switch v[1].(type) {
+ case []interface{}:
+ default:
+ if i == 0 && doIndent {
+ p.Indent()
+ }
+ }
+ i++
+ if err := mapToXmlIndent(doIndent, s, v[0].(string), v[1], p); err != nil {
+ return err
+ }
+ switch v[1].(type) {
+ case []interface{}: // handled in []interface{} case
+ default:
+ if doIndent {
+ p.Outdent()
+ }
+ }
+ i--
+ }
+ p.mapDepth--
+ endTag = true
+ elen = 1 // we do have some content ...
+ case []interface{}:
+ // special case - found during implementing Issue #23
+ if len(value.([]interface{})) == 0 {
+ if doIndent {
+ *s += p.padding + p.indent
+ }
+ *s += "<" + key
+ elen = 0
+ endTag = true
+ break
+ }
+ for _, v := range value.([]interface{}) {
+ if doIndent {
+ p.Indent()
+ }
+ if err := mapToXmlIndent(doIndent, s, key, v, p); err != nil {
+ return err
+ }
+ if doIndent {
+ p.Outdent()
+ }
+ }
+ return nil
+ case []string:
+ // This was added by https://github.com/slotix ... not a type that
+ // would be encountered if mv generated from NewMapXml, NewMapJson.
+ // Could be encountered in AnyXml(), so we'll let it stay, though
+ // it should be merged with case []interface{}, above.
+ //quick fix for []string type
+ //[]string should be treated exaclty as []interface{}
+ if len(value.([]string)) == 0 {
+ if doIndent {
+ *s += p.padding + p.indent
+ }
+ *s += "<" + key
+ elen = 0
+ endTag = true
+ break
+ }
+ for _, v := range value.([]string) {
+ if doIndent {
+ p.Indent()
+ }
+ if err := mapToXmlIndent(doIndent, s, key, v, p); err != nil {
+ return err
+ }
+ if doIndent {
+ p.Outdent()
+ }
+ }
+ return nil
+ case nil:
+ // terminate the tag
+ if doIndent {
+ *s += p.padding
+ }
+ *s += "<" + key
+ endTag, isSimple = true, true
+ break
+ default: // handle anything - even goofy stuff
+ elen = 0
+ switch value.(type) {
+ case string:
+ v := value.(string)
+ if xmlEscapeChars {
+ v = escapeChars(v)
+ }
+ elen = len(v)
+ if elen > 0 {
+ *s += ">" + v
+ }
+ case float64, bool, int, int32, int64, float32, json.Number:
+ v := fmt.Sprintf("%v", value)
+ elen = len(v) // always > 0
+ *s += ">" + v
+ case []byte: // NOTE: byte is just an alias for uint8
+ // similar to how xml.Marshal handles []byte structure members
+ v := string(value.([]byte))
+ if xmlEscapeChars {
+ v = escapeChars(v)
+ }
+ elen = len(v)
+ if elen > 0 {
+ *s += ">" + v
+ }
+ default:
+ var v []byte
+ var err error
+ if doIndent {
+ v, err = xml.MarshalIndent(value, p.padding, p.indent)
+ } else {
+ v, err = xml.Marshal(value)
+ }
+ if err != nil {
+ *s += ">UNKNOWN"
+ } else {
+ elen = len(v)
+ if elen > 0 {
+ *s += string(v)
+ }
+ }
+ }
+ isSimple = true
+ endTag = true
+ }
+ if endTag {
+ if doIndent {
+ if !isSimple {
+ *s += p.padding
+ }
+ }
+ if elen > 0 || useGoXmlEmptyElemSyntax {
+ if elen == 0 {
+ *s += ">"
+ }
+ *s += `` + key + ">"
+ } else {
+ *s += `/>`
+ }
+ }
+ if doIndent {
+ if p.cnt > p.start {
+ *s += "\n"
+ }
+ p.Outdent()
+ }
+
+ return nil
+}
+
+// ============================ sort interface implementation =================
+
+type attrList [][2]string
+
+func (a attrList) Len() int {
+ return len(a)
+}
+
+func (a attrList) Swap(i, j int) {
+ a[i], a[j] = a[j], a[i]
+}
+
+func (a attrList) Less(i, j int) bool {
+ return a[i][0] <= a[j][0]
+}
+
+type elemList [][2]interface{}
+
+func (e elemList) Len() int {
+ return len(e)
+}
+
+func (e elemList) Swap(i, j int) {
+ e[i], e[j] = e[j], e[i]
+}
+
+func (e elemList) Less(i, j int) bool {
+ return e[i][0].(string) <= e[j][0].(string)
+}
diff --git a/vendor/github.com/clbanning/mxj/xmlseq.go b/vendor/github.com/clbanning/mxj/xmlseq.go
new file mode 100644
index 0000000..6be73ae
--- /dev/null
+++ b/vendor/github.com/clbanning/mxj/xmlseq.go
@@ -0,0 +1,828 @@
+// Copyright 2012-2016 Charles Banning. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file
+
+// xmlseq.go - version of xml.go with sequence # injection on Decoding and sorting on Encoding.
+// Also, handles comments, directives and process instructions.
+
+package mxj
+
+import (
+ "bytes"
+ "encoding/xml"
+ "errors"
+ "fmt"
+ "io"
+ "sort"
+ "strings"
+)
+
+var NoRoot = errors.New("no root key")
+var NO_ROOT = NoRoot // maintain backwards compatibility
+
+// ------------------- NewMapXmlSeq & NewMapXmlSeqReader ... -------------------------
+
+// This is only useful if you want to re-encode the Map as XML using mv.XmlSeq(), etc., to preserve the original structure.
+// The xml.Decoder.RawToken method is used to parse the XML, so there is no checking for appropriate xml.EndElement values;
+// thus, it is assumed that the XML is valid.
+//
+// NewMapXmlSeq - convert a XML doc into a Map with elements id'd with decoding sequence int - #seq.
+// If the optional argument 'cast' is 'true', then values will be converted to boolean or float64 if possible.
+// NOTE: "#seq" key/value pairs are removed on encoding with mv.XmlSeq() / mv.XmlSeqIndent().
+// • attributes are a map - map["#attr"]map["attr_key"]map[string]interface{}{"#text":, "#seq":}
+// • all simple elements are decoded as map["#text"]interface{} with a "#seq" k:v pair, as well.
+// • lists always decode as map["list_tag"][]map[string]interface{} where the array elements are maps that
+// include a "#seq" k:v pair based on sequence they are decoded. Thus, XML like:
+//
+// value 1
+// value 2
+// value 3
+//
+// is decoded as:
+// doc :
+// ltag :[[]interface{}]
+// [item: 0]
+// #seq :[int] 0
+// #text :[string] value 1
+// [item: 1]
+// #seq :[int] 2
+// #text :[string] value 3
+// newtag :
+// #seq :[int] 1
+// #text :[string] value 2
+// It will encode in proper sequence even though the Map representation merges all "ltag" elements in an array.
+// • comments - "" - are decoded as map["#comment"]map["#text"]"cmnt_text" with a "#seq" k:v pair.
+// • directives - "" - are decoded as map["#directive"]map[#text"]"directive_text" with a "#seq" k:v pair.
+// • process instructions - "" - are decoded as map["#procinst"]interface{} where the #procinst value
+// is of map[string]interface{} type with the following keys: #target, #inst, and #seq.
+// • comments, directives, and procinsts that are NOT part of a document with a root key will be returned as
+// map[string]interface{} and the error value 'NoRoot'.
+// • note: ": tag preserve the
+// ":" notation rather than stripping it as with NewMapXml().
+// 2. Attribute keys for name space prefix declarations preserve "xmlns:" notation.
+func NewMapXmlSeq(xmlVal []byte, cast ...bool) (Map, error) {
+ var r bool
+ if len(cast) == 1 {
+ r = cast[0]
+ }
+ return xmlSeqToMap(xmlVal, r)
+}
+
+// This is only useful if you want to re-encode the Map as XML using mv.XmlSeq(), etc., to preserve the original structure.
+//
+// Get next XML doc from an io.Reader as a Map value. Returns Map value.
+// NOTES:
+// 1. The 'xmlReader' will be parsed looking for an xml.StartElement, xml.Comment, etc., so BOM and other
+// extraneous xml.CharData will be ignored unless io.EOF is reached first.
+// 2. CoerceKeysToLower() is NOT recognized, since the intent here is to eventually call m.XmlSeq() to
+// re-encode the message in its original structure.
+// 3. If CoerceKeysToSnakeCase() has been called, then all key values will be converted to snake case.
+func NewMapXmlSeqReader(xmlReader io.Reader, cast ...bool) (Map, error) {
+ var r bool
+ if len(cast) == 1 {
+ r = cast[0]
+ }
+
+ // We need to put an *os.File reader in a ByteReader or the xml.NewDecoder
+ // will wrap it in a bufio.Reader and seek on the file beyond where the
+ // xml.Decoder parses!
+ if _, ok := xmlReader.(io.ByteReader); !ok {
+ xmlReader = myByteReader(xmlReader) // see code at EOF
+ }
+
+ // build the map
+ return xmlSeqReaderToMap(xmlReader, r)
+}
+
+// This is only useful if you want to re-encode the Map as XML using mv.XmlSeq(), etc., to preserve the original structure.
+//
+// Get next XML doc from an io.Reader as a Map value. Returns Map value and slice with the raw XML.
+// NOTES:
+// 1. Due to the implementation of xml.Decoder, the raw XML off the reader is buffered to []byte
+// using a ByteReader. If the io.Reader is an os.File, there may be significant performance impact.
+// See the examples - getmetrics1.go through getmetrics4.go - for comparative use cases on a large
+// data set. If the io.Reader is wrapping a []byte value in-memory, however, such as http.Request.Body
+// you CAN use it to efficiently unmarshal a XML doc and retrieve the raw XML in a single call.
+// 2. The 'raw' return value may be larger than the XML text value.
+// 3. The 'xmlReader' will be parsed looking for an xml.StartElement, xml.Comment, etc., so BOM and other
+// extraneous xml.CharData will be ignored unless io.EOF is reached first.
+// 4. CoerceKeysToLower() is NOT recognized, since the intent here is to eventually call m.XmlSeq() to
+// re-encode the message in its original structure.
+// 5. If CoerceKeysToSnakeCase() has been called, then all key values will be converted to snake case.
+func NewMapXmlSeqReaderRaw(xmlReader io.Reader, cast ...bool) (Map, []byte, error) {
+ var r bool
+ if len(cast) == 1 {
+ r = cast[0]
+ }
+ // create TeeReader so we can retrieve raw XML
+ buf := make([]byte, 0)
+ wb := bytes.NewBuffer(buf)
+ trdr := myTeeReader(xmlReader, wb)
+
+ m, err := xmlSeqReaderToMap(trdr, r)
+
+ // retrieve the raw XML that was decoded
+ b := wb.Bytes()
+
+ // err may be NoRoot
+ return m, b, err
+}
+
+// xmlSeqReaderToMap() - parse a XML io.Reader to a map[string]interface{} value
+func xmlSeqReaderToMap(rdr io.Reader, r bool) (map[string]interface{}, error) {
+ // parse the Reader
+ p := xml.NewDecoder(rdr)
+ if CustomDecoder != nil {
+ useCustomDecoder(p)
+ } else {
+ p.CharsetReader = XmlCharsetReader
+ }
+ return xmlSeqToMapParser("", nil, p, r)
+}
+
+// xmlSeqToMap - convert a XML doc into map[string]interface{} value
+func xmlSeqToMap(doc []byte, r bool) (map[string]interface{}, error) {
+ b := bytes.NewReader(doc)
+ p := xml.NewDecoder(b)
+ if CustomDecoder != nil {
+ useCustomDecoder(p)
+ } else {
+ p.CharsetReader = XmlCharsetReader
+ }
+ return xmlSeqToMapParser("", nil, p, r)
+}
+
+// ===================================== where the work happens =============================
+
+// xmlSeqToMapParser - load a 'clean' XML doc into a map[string]interface{} directly.
+// Add #seq tag value for each element decoded - to be used for Encoding later.
+func xmlSeqToMapParser(skey string, a []xml.Attr, p *xml.Decoder, r bool) (map[string]interface{}, error) {
+ if snakeCaseKeys {
+ skey = strings.Replace(skey, "-", "_", -1)
+ }
+
+ // NOTE: all attributes and sub-elements parsed into 'na', 'na' is returned as value for 'skey' in 'n'.
+ var n, na map[string]interface{}
+ var seq int // for including seq num when decoding
+
+ // Allocate maps and load attributes, if any.
+ // NOTE: on entry from NewMapXml(), etc., skey=="", and we fall through
+ // to get StartElement then recurse with skey==xml.StartElement.Name.Local
+ // where we begin allocating map[string]interface{} values 'n' and 'na'.
+ if skey != "" {
+ // 'n' only needs one slot - save call to runtime•hashGrow()
+ // 'na' we don't know
+ n = make(map[string]interface{}, 1)
+ na = make(map[string]interface{})
+ if len(a) > 0 {
+ // xml.Attr is decoded into: map["#attr"]map[]interface{}
+ // where interface{} is map[string]interface{}{"#text":, "#seq":}
+ aa := make(map[string]interface{}, len(a))
+ for i, v := range a {
+ if snakeCaseKeys {
+ v.Name.Local = strings.Replace(v.Name.Local, "-", "_", -1)
+ }
+ if len(v.Name.Space) > 0 {
+ aa[v.Name.Space+`:`+v.Name.Local] = map[string]interface{}{"#text": cast(v.Value, r), "#seq": i}
+ } else {
+ aa[v.Name.Local] = map[string]interface{}{"#text": cast(v.Value, r), "#seq": i}
+ }
+ }
+ na["#attr"] = aa
+ }
+ }
+
+ // Return XMPP message.
+ if handleXMPPStreamTag && skey == "stream:stream" {
+ n[skey] = na
+ return n, nil
+ }
+
+ for {
+ t, err := p.RawToken()
+ if err != nil {
+ if err != io.EOF {
+ return nil, errors.New("xml.Decoder.Token() - " + err.Error())
+ }
+ return nil, err
+ }
+ switch t.(type) {
+ case xml.StartElement:
+ tt := t.(xml.StartElement)
+
+ // First call to xmlSeqToMapParser() doesn't pass xml.StartElement - the map key.
+ // So when the loop is first entered, the first token is the root tag along
+ // with any attributes, which we process here.
+ //
+ // Subsequent calls to xmlSeqToMapParser() will pass in tag+attributes for
+ // processing before getting the next token which is the element value,
+ // which is done above.
+ if skey == "" {
+ if len(tt.Name.Space) > 0 {
+ return xmlSeqToMapParser(tt.Name.Space+`:`+tt.Name.Local, tt.Attr, p, r)
+ } else {
+ return xmlSeqToMapParser(tt.Name.Local, tt.Attr, p, r)
+ }
+ }
+
+ // If not initializing the map, parse the element.
+ // len(nn) == 1, necessarily - it is just an 'n'.
+ var nn map[string]interface{}
+ if len(tt.Name.Space) > 0 {
+ nn, err = xmlSeqToMapParser(tt.Name.Space+`:`+tt.Name.Local, tt.Attr, p, r)
+ } else {
+ nn, err = xmlSeqToMapParser(tt.Name.Local, tt.Attr, p, r)
+ }
+ if err != nil {
+ return nil, err
+ }
+
+ // The nn map[string]interface{} value is a na[nn_key] value.
+ // We need to see if nn_key already exists - means we're parsing a list.
+ // This may require converting na[nn_key] value into []interface{} type.
+ // First, extract the key:val for the map - it's a singleton.
+ var key string
+ var val interface{}
+ for key, val = range nn {
+ break
+ }
+
+ // add "#seq" k:v pair -
+ // Sequence number included even in list elements - this should allow us
+ // to properly resequence even something goofy like:
+ // item 1
+ // item 2
+ // item 3
+ // where all the "list" subelements are decoded into an array.
+ switch val.(type) {
+ case map[string]interface{}:
+ val.(map[string]interface{})["#seq"] = seq
+ seq++
+ case interface{}: // a non-nil simple element: string, float64, bool
+ v := map[string]interface{}{"#text": val, "#seq": seq}
+ seq++
+ val = v
+ }
+
+ // 'na' holding sub-elements of n.
+ // See if 'key' already exists.
+ // If 'key' exists, then this is a list, if not just add key:val to na.
+ if v, ok := na[key]; ok {
+ var a []interface{}
+ switch v.(type) {
+ case []interface{}:
+ a = v.([]interface{})
+ default: // anything else - note: v.(type) != nil
+ a = []interface{}{v}
+ }
+ a = append(a, val)
+ na[key] = a
+ } else {
+ na[key] = val // save it as a singleton
+ }
+ case xml.EndElement:
+ if skey != "" {
+ tt := t.(xml.EndElement)
+ if snakeCaseKeys {
+ tt.Name.Local = strings.Replace(tt.Name.Local, "-", "_", -1)
+ }
+ var name string
+ if len(tt.Name.Space) > 0 {
+ name = tt.Name.Space + `:` + tt.Name.Local
+ } else {
+ name = tt.Name.Local
+ }
+ if skey != name {
+ return nil, fmt.Errorf("element %s not properly terminated, got %s at #%d",
+ skey, name, p.InputOffset())
+ }
+ }
+ // len(n) > 0 if this is a simple element w/o xml.Attrs - see xml.CharData case.
+ if len(n) == 0 {
+ // If len(na)==0 we have an empty element == "";
+ // it has no xml.Attr nor xml.CharData.
+ // Empty element content will be map["etag"]map["#text"]""
+ // after #seq injection - map["etag"]map["#seq"]seq - after return.
+ if len(na) > 0 {
+ n[skey] = na
+ } else {
+ n[skey] = "" // empty element
+ }
+ }
+ return n, nil
+ case xml.CharData:
+ // clean up possible noise
+ tt := strings.Trim(string(t.(xml.CharData)), "\t\r\b\n ")
+ if skey == "" {
+ // per Adrian (http://www.adrianlungu.com/) catch stray text
+ // in decoder stream -
+ // https://github.com/clbanning/mxj/pull/14#issuecomment-182816374
+ // NOTE: CharSetReader must be set to non-UTF-8 CharSet or you'll get
+ // a p.Token() decoding error when the BOM is UTF-16 or UTF-32.
+ continue
+ }
+ if len(tt) > 0 {
+ // every simple element is a #text and has #seq associated with it
+ na["#text"] = cast(tt, r)
+ na["#seq"] = seq
+ seq++
+ }
+ case xml.Comment:
+ if n == nil { // no root 'key'
+ n = map[string]interface{}{"#comment": string(t.(xml.Comment))}
+ return n, NoRoot
+ }
+ cm := make(map[string]interface{}, 2)
+ cm["#text"] = string(t.(xml.Comment))
+ cm["#seq"] = seq
+ seq++
+ na["#comment"] = cm
+ case xml.Directive:
+ if n == nil { // no root 'key'
+ n = map[string]interface{}{"#directive": string(t.(xml.Directive))}
+ return n, NoRoot
+ }
+ dm := make(map[string]interface{}, 2)
+ dm["#text"] = string(t.(xml.Directive))
+ dm["#seq"] = seq
+ seq++
+ na["#directive"] = dm
+ case xml.ProcInst:
+ if n == nil {
+ na = map[string]interface{}{"#target": t.(xml.ProcInst).Target, "#inst": string(t.(xml.ProcInst).Inst)}
+ n = map[string]interface{}{"#procinst": na}
+ return n, NoRoot
+ }
+ pm := make(map[string]interface{}, 3)
+ pm["#target"] = t.(xml.ProcInst).Target
+ pm["#inst"] = string(t.(xml.ProcInst).Inst)
+ pm["#seq"] = seq
+ seq++
+ na["#procinst"] = pm
+ default:
+ // noop - shouldn't ever get here, now, since we handle all token types
+ }
+ }
+}
+
+// ------------------ END: NewMapXml & NewMapXmlReader -------------------------
+
+// --------------------- mv.XmlSeq & mv.XmlSeqWriter -------------------------
+
+// This should ONLY be used on Map values that were decoded using NewMapXmlSeq() & co.
+//
+// Encode a Map as XML with elements sorted on #seq. The companion of NewMapXmlSeq().
+// The following rules apply.
+// - The key label "#text" is treated as the value for a simple element with attributes.
+// - The "#seq" key is used to seqence the subelements or attributes but is ignored for writing.
+// - The "#attr" map key identifies the map of attribute map[string]interface{} values with "#text" key.
+// - The "#comment" map key identifies a comment in the value "#text" map entry - .
+// - The "#directive" map key identifies a directive in the value "#text" map entry - .
+// - The "#procinst" map key identifies a process instruction in the value "#target" and "#inst"
+// map entries - .
+// - Value type encoding:
+// > string, bool, float64, int, int32, int64, float32: per "%v" formating
+// > []bool, []uint8: by casting to string
+// > structures, etc.: handed to xml.Marshal() - if there is an error, the element
+// value is "UNKNOWN"
+// - Elements with only attribute values or are null are terminated using "/>" unless XmlGoEmptyElemSystax() called.
+// - If len(mv) == 1 and no rootTag is provided, then the map key is used as the root tag, possible.
+// Thus, `{ "key":"value" }` encodes as "value".
+func (mv Map) XmlSeq(rootTag ...string) ([]byte, error) {
+ m := map[string]interface{}(mv)
+ var err error
+ s := new(string)
+ p := new(pretty) // just a stub
+
+ if len(m) == 1 && len(rootTag) == 0 {
+ for key, value := range m {
+ // if it's an array, see if all values are map[string]interface{}
+ // we force a new root tag if we'll end up with no key:value in the list
+ // so: key:[string_val, bool:true] --> string_valtrue
+ switch value.(type) {
+ case []interface{}:
+ for _, v := range value.([]interface{}) {
+ switch v.(type) {
+ case map[string]interface{}: // noop
+ default: // anything else
+ err = mapToXmlSeqIndent(false, s, DefaultRootTag, m, p)
+ goto done
+ }
+ }
+ }
+ err = mapToXmlSeqIndent(false, s, key, value, p)
+ }
+ } else if len(rootTag) == 1 {
+ err = mapToXmlSeqIndent(false, s, rootTag[0], m, p)
+ } else {
+ err = mapToXmlSeqIndent(false, s, DefaultRootTag, m, p)
+ }
+done:
+ return []byte(*s), err
+}
+
+// The following implementation is provided only for symmetry with NewMapXmlReader[Raw]
+// The names will also provide a key for the number of return arguments.
+
+// This should ONLY be used on Map values that were decoded using NewMapXmlSeq() & co.
+//
+// Writes the Map as XML on the Writer.
+// See XmlSeq() for encoding rules.
+func (mv Map) XmlSeqWriter(xmlWriter io.Writer, rootTag ...string) error {
+ x, err := mv.XmlSeq(rootTag...)
+ if err != nil {
+ return err
+ }
+
+ _, err = xmlWriter.Write(x)
+ return err
+}
+
+// This should ONLY be used on Map values that were decoded using NewMapXmlSeq() & co.
+//
+// Writes the Map as XML on the Writer. []byte is the raw XML that was written.
+// See XmlSeq() for encoding rules.
+func (mv Map) XmlSeqWriterRaw(xmlWriter io.Writer, rootTag ...string) ([]byte, error) {
+ x, err := mv.XmlSeq(rootTag...)
+ if err != nil {
+ return x, err
+ }
+
+ _, err = xmlWriter.Write(x)
+ return x, err
+}
+
+// This should ONLY be used on Map values that were decoded using NewMapXmlSeq() & co.
+//
+// Writes the Map as pretty XML on the Writer.
+// See Xml() for encoding rules.
+func (mv Map) XmlSeqIndentWriter(xmlWriter io.Writer, prefix, indent string, rootTag ...string) error {
+ x, err := mv.XmlSeqIndent(prefix, indent, rootTag...)
+ if err != nil {
+ return err
+ }
+
+ _, err = xmlWriter.Write(x)
+ return err
+}
+
+// This should ONLY be used on Map values that were decoded using NewMapXmlSeq() & co.
+//
+// Writes the Map as pretty XML on the Writer. []byte is the raw XML that was written.
+// See XmlSeq() for encoding rules.
+func (mv Map) XmlSeqIndentWriterRaw(xmlWriter io.Writer, prefix, indent string, rootTag ...string) ([]byte, error) {
+ x, err := mv.XmlSeqIndent(prefix, indent, rootTag...)
+ if err != nil {
+ return x, err
+ }
+
+ _, err = xmlWriter.Write(x)
+ return x, err
+}
+
+// -------------------- END: mv.Xml & mv.XmlWriter -------------------------------
+
+// ---------------------- XmlSeqIndent ----------------------------
+
+// This should ONLY be used on Map values that were decoded using NewMapXmlSeq() & co.
+//
+// Encode a map[string]interface{} as a pretty XML string.
+// See mv.XmlSeq() for encoding rules.
+func (mv Map) XmlSeqIndent(prefix, indent string, rootTag ...string) ([]byte, error) {
+ m := map[string]interface{}(mv)
+
+ var err error
+ s := new(string)
+ p := new(pretty)
+ p.indent = indent
+ p.padding = prefix
+
+ if len(m) == 1 && len(rootTag) == 0 {
+ // this can extract the key for the single map element
+ // use it if it isn't a key for a list
+ for key, value := range m {
+ if _, ok := value.([]interface{}); ok {
+ err = mapToXmlSeqIndent(true, s, DefaultRootTag, m, p)
+ } else {
+ err = mapToXmlSeqIndent(true, s, key, value, p)
+ }
+ }
+ } else if len(rootTag) == 1 {
+ err = mapToXmlSeqIndent(true, s, rootTag[0], m, p)
+ } else {
+ err = mapToXmlSeqIndent(true, s, DefaultRootTag, m, p)
+ }
+ return []byte(*s), err
+}
+
+// where the work actually happens
+// returns an error if an attribute is not atomic
+func mapToXmlSeqIndent(doIndent bool, s *string, key string, value interface{}, pp *pretty) error {
+ var endTag bool
+ var isSimple bool
+ var noEndTag bool
+ var elen int
+ var ss string
+ p := &pretty{pp.indent, pp.cnt, pp.padding, pp.mapDepth, pp.start}
+
+ switch value.(type) {
+ case map[string]interface{}, []byte, string, float64, bool, int, int32, int64, float32:
+ if doIndent {
+ *s += p.padding
+ }
+ if key != "#comment" && key != "#directive" && key != "#procinst" {
+ *s += `<` + key
+ }
+ }
+ switch value.(type) {
+ case map[string]interface{}:
+ val := value.(map[string]interface{})
+
+ if key == "#comment" {
+ *s += ``
+ noEndTag = true
+ break
+ }
+
+ if key == "#directive" {
+ *s += ``
+ noEndTag = true
+ break
+ }
+
+ if key == "#procinst" {
+ *s += `` + val["#target"].(string) + ` ` + val["#inst"].(string) + `?>`
+ noEndTag = true
+ break
+ }
+
+ haveAttrs := false
+ // process attributes first
+ if v, ok := val["#attr"].(map[string]interface{}); ok {
+ // First, unroll the map[string]interface{} into a []keyval array.
+ // Then sequence it.
+ kv := make([]keyval, len(v))
+ n := 0
+ for ak, av := range v {
+ kv[n] = keyval{ak, av}
+ n++
+ }
+ sort.Sort(elemListSeq(kv))
+ // Now encode the attributes in original decoding sequence, using keyval array.
+ for _, a := range kv {
+ vv := a.v.(map[string]interface{})
+ switch vv["#text"].(type) {
+ case string:
+ if xmlEscapeChars {
+ ss = escapeChars(vv["#text"].(string))
+ } else {
+ ss = vv["#text"].(string)
+ }
+ *s += ` ` + a.k + `="` + ss + `"`
+ case float64, bool, int, int32, int64, float32:
+ *s += ` ` + a.k + `="` + fmt.Sprintf("%v", vv["#text"]) + `"`
+ case []byte:
+ if xmlEscapeChars {
+ ss = escapeChars(string(vv["#text"].([]byte)))
+ } else {
+ ss = string(vv["#text"].([]byte))
+ }
+ *s += ` ` + a.k + `="` + ss + `"`
+ default:
+ return fmt.Errorf("invalid attribute value for: %s", a.k)
+ }
+ }
+ haveAttrs = true
+ }
+
+ // simple element?
+ // every map value has, at least, "#seq" and, perhaps, "#text" and/or "#attr"
+ _, seqOK := val["#seq"] // have key
+ if v, ok := val["#text"]; ok && ((len(val) == 3 && haveAttrs) || (len(val) == 2 && !haveAttrs)) && seqOK {
+ if stmp, ok := v.(string); ok && stmp != "" {
+ if xmlEscapeChars {
+ stmp = escapeChars(stmp)
+ }
+ *s += ">" + stmp
+ endTag = true
+ elen = 1
+ }
+ isSimple = true
+ break
+ } else if !ok && ((len(val) == 2 && haveAttrs) || (len(val) == 1 && !haveAttrs)) && seqOK {
+ // here no #text but have #seq or #seq+#attr
+ endTag = false
+ break
+ }
+
+ // we now need to sequence everything except attributes
+ // 'kv' will hold everything that needs to be written
+ kv := make([]keyval, 0)
+ for k, v := range val {
+ if k == "#attr" { // already processed
+ continue
+ }
+ if k == "#seq" { // ignore - just for sorting
+ continue
+ }
+ switch v.(type) {
+ case []interface{}:
+ // unwind the array as separate entries
+ for _, vv := range v.([]interface{}) {
+ kv = append(kv, keyval{k, vv})
+ }
+ default:
+ kv = append(kv, keyval{k, v})
+ }
+ }
+
+ // close tag with possible attributes
+ *s += ">"
+ if doIndent {
+ *s += "\n"
+ }
+ // something more complex
+ p.mapDepth++
+ sort.Sort(elemListSeq(kv))
+ i := 0
+ for _, v := range kv {
+ switch v.v.(type) {
+ case []interface{}:
+ default:
+ if i == 0 && doIndent {
+ p.Indent()
+ }
+ }
+ i++
+ if err := mapToXmlSeqIndent(doIndent, s, v.k, v.v, p); err != nil {
+ return err
+ }
+ switch v.v.(type) {
+ case []interface{}: // handled in []interface{} case
+ default:
+ if doIndent {
+ p.Outdent()
+ }
+ }
+ i--
+ }
+ p.mapDepth--
+ endTag = true
+ elen = 1 // we do have some content other than attrs
+ case []interface{}:
+ for _, v := range value.([]interface{}) {
+ if doIndent {
+ p.Indent()
+ }
+ if err := mapToXmlSeqIndent(doIndent, s, key, v, p); err != nil {
+ return err
+ }
+ if doIndent {
+ p.Outdent()
+ }
+ }
+ return nil
+ case nil:
+ // terminate the tag
+ if doIndent {
+ *s += p.padding
+ }
+ *s += "<" + key
+ endTag, isSimple = true, true
+ break
+ default: // handle anything - even goofy stuff
+ elen = 0
+ switch value.(type) {
+ case string:
+ if xmlEscapeChars {
+ ss = escapeChars(value.(string))
+ } else {
+ ss = value.(string)
+ }
+ elen = len(ss)
+ if elen > 0 {
+ *s += ">" + ss
+ }
+ case float64, bool, int, int32, int64, float32:
+ v := fmt.Sprintf("%v", value)
+ elen = len(v)
+ if elen > 0 {
+ *s += ">" + v
+ }
+ case []byte: // NOTE: byte is just an alias for uint8
+ // similar to how xml.Marshal handles []byte structure members
+ if xmlEscapeChars {
+ ss = escapeChars(string(value.([]byte)))
+ } else {
+ ss = string(value.([]byte))
+ }
+ elen = len(ss)
+ if elen > 0 {
+ *s += ">" + ss
+ }
+ default:
+ var v []byte
+ var err error
+ if doIndent {
+ v, err = xml.MarshalIndent(value, p.padding, p.indent)
+ } else {
+ v, err = xml.Marshal(value)
+ }
+ if err != nil {
+ *s += ">UNKNOWN"
+ } else {
+ elen = len(v)
+ if elen > 0 {
+ *s += string(v)
+ }
+ }
+ }
+ isSimple = true
+ endTag = true
+ }
+ if endTag && !noEndTag {
+ if doIndent {
+ if !isSimple {
+ *s += p.padding
+ }
+ }
+ switch value.(type) {
+ case map[string]interface{}, []byte, string, float64, bool, int, int32, int64, float32:
+ if elen > 0 || useGoXmlEmptyElemSyntax {
+ if elen == 0 {
+ *s += ">"
+ }
+ *s += `` + key + ">"
+ } else {
+ *s += `/>`
+ }
+ }
+ } else if !noEndTag {
+ if useGoXmlEmptyElemSyntax {
+ *s += `` + key + ">"
+ // *s += ">" + key + ">"
+ } else {
+ *s += "/>"
+ }
+ }
+ if doIndent {
+ if p.cnt > p.start {
+ *s += "\n"
+ }
+ p.Outdent()
+ }
+
+ return nil
+}
+
+// the element sort implementation
+
+type keyval struct {
+ k string
+ v interface{}
+}
+type elemListSeq []keyval
+
+func (e elemListSeq) Len() int {
+ return len(e)
+}
+
+func (e elemListSeq) Swap(i, j int) {
+ e[i], e[j] = e[j], e[i]
+}
+
+func (e elemListSeq) Less(i, j int) bool {
+ var iseq, jseq int
+ var ok bool
+ if iseq, ok = e[i].v.(map[string]interface{})["#seq"].(int); !ok {
+ iseq = 9999999
+ }
+
+ if jseq, ok = e[j].v.(map[string]interface{})["#seq"].(int); !ok {
+ jseq = 9999999
+ }
+
+ return iseq <= jseq
+}
+
+// =============== https://groups.google.com/forum/#!topic/golang-nuts/lHPOHD-8qio
+
+// BeautifyXml (re)formats an XML doc similar to Map.XmlIndent().
+func BeautifyXml(b []byte, prefix, indent string) ([]byte, error) {
+ x, err := NewMapXmlSeq(b)
+ if err != nil {
+ return nil, err
+ }
+ return x.XmlSeqIndent(prefix, indent)
+}
diff --git a/vendor/github.com/codegangsta/negroni/.gitignore b/vendor/github.com/codegangsta/negroni/.gitignore
deleted file mode 100644
index 3f2bc47..0000000
--- a/vendor/github.com/codegangsta/negroni/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-/coverage.txt
diff --git a/vendor/github.com/codegangsta/negroni/.travis.yml b/vendor/github.com/codegangsta/negroni/.travis.yml
deleted file mode 100644
index 1810433..0000000
--- a/vendor/github.com/codegangsta/negroni/.travis.yml
+++ /dev/null
@@ -1,27 +0,0 @@
-language: go
-
-sudo: false
-dist: trusty
-
-go:
-- 1.x
-- 1.2.x
-- 1.3.x
-- 1.4.x
-- 1.5.x
-- 1.6.x
-- 1.7.x
-- 1.8.x
-- master
-
-before_install:
-- find "${GOPATH%%:*}" -name '*.a' -delete
-- rm -rf "${GOPATH%%:*}/src/golang.org"
-- go get golang.org/x/tools/cover
-- go get golang.org/x/tools/cmd/cover
-
-script:
-- go test -race -coverprofile=coverage.txt -covermode=atomic
-
-after_success:
-- bash <(curl -s "https://codecov.io/bash")
diff --git a/vendor/github.com/codegangsta/negroni/CHANGELOG.md b/vendor/github.com/codegangsta/negroni/CHANGELOG.md
deleted file mode 100644
index 1b757d0..0000000
--- a/vendor/github.com/codegangsta/negroni/CHANGELOG.md
+++ /dev/null
@@ -1,37 +0,0 @@
-# Change Log
-
-**ATTN**: This project uses [semantic versioning](http://semver.org/).
-
-## [Unreleased]
-### Added
-- `Recovery.ErrorHandlerFunc` for custom error handling during recovery
-- `With()` helper for building a new `Negroni` struct chaining handlers from
- existing `Negroni` structs
-
-### Fixed
-- `Written()` correct returns `false` if no response header has been written
-
-### Changed
-- Set default status to `0` in the case that no handler writes status -- was
- previously `200` (in 0.2.0, before that it was `0` so this reestablishes that
- behavior)
-- Catch `panic`s thrown by callbacks provided to the `Recovery` handler
-
-## [0.2.0] - 2016-05-10
-### Added
-- Support for variadic handlers in `New()`
-- Added `Negroni.Handlers()` to fetch all of the handlers for a given chain
-- Allowed size in `Recovery` handler was bumped to 8k
-- `Negroni.UseFunc` to push another handler onto the chain
-
-### Changed
-- Set the status before calling `beforeFuncs` so the information is available to them
-- Set default status to `200` in the case that no handler writes status -- was previously `0`
-- Panic if `nil` handler is given to `negroni.Use`
-
-## 0.1.0 - 2013-07-22
-### Added
-- Initial implementation.
-
-[Unreleased]: https://github.com/urfave/negroni/compare/v0.2.0...HEAD
-[0.2.0]: https://github.com/urfave/negroni/compare/v0.1.0...v0.2.0
diff --git a/vendor/github.com/codegangsta/negroni/README.md b/vendor/github.com/codegangsta/negroni/README.md
deleted file mode 100644
index 997acbd..0000000
--- a/vendor/github.com/codegangsta/negroni/README.md
+++ /dev/null
@@ -1,546 +0,0 @@
-# Negroni
-[](http://godoc.org/github.com/urfave/negroni)
-[](https://travis-ci.org/urfave/negroni)
-[](https://codebeat.co/projects/github-com-urfave-negroni)
-[](https://codecov.io/gh/urfave/negroni)
-
-**Notice:** This is the library formerly known as
-`github.com/codegangsta/negroni` -- Github will automatically redirect requests
-to this repository, but we recommend updating your references for clarity.
-
-Negroni is an idiomatic approach to web middleware in Go. It is tiny,
-non-intrusive, and encourages use of `net/http` Handlers.
-
-If you like the idea of [Martini](https://github.com/go-martini/martini), but
-you think it contains too much magic, then Negroni is a great fit.
-
-Language Translations:
-* [Deutsch (de_DE)](translations/README_de_de.md)
-* [Português Brasileiro (pt_BR)](translations/README_pt_br.md)
-* [简体中文 (zh_cn)](translations/README_zh_cn.md)
-* [繁體中文 (zh_tw)](translations/README_zh_tw.md)
-* [日本語 (ja_JP)](translations/README_ja_JP.md)
-* [Français (fr_FR)](translations/README_fr_FR.md)
-
-## Getting Started
-
-After installing Go and setting up your
-[GOPATH](http://golang.org/doc/code.html#GOPATH), create your first `.go` file.
-We'll call it `server.go`.
-
-
-``` go
-package main
-
-import (
- "fmt"
- "net/http"
-
- "github.com/urfave/negroni"
-)
-
-func main() {
- mux := http.NewServeMux()
- mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
- fmt.Fprintf(w, "Welcome to the home page!")
- })
-
- n := negroni.Classic() // Includes some default middlewares
- n.UseHandler(mux)
-
- http.ListenAndServe(":3000", n)
-}
-```
-
-Then install the Negroni package (**NOTE**: >= **go 1.1** is required):
-
-```
-go get github.com/urfave/negroni
-```
-
-Then run your server:
-
-```
-go run server.go
-```
-
-You will now have a Go `net/http` webserver running on `localhost:3000`.
-
-### Packaging
-
-If you are on Debian, `negroni` is also available as [a
-package](https://packages.debian.org/sid/golang-github-urfave-negroni-dev) that
-you can install via `apt install golang-github-urfave-negroni-dev` (at the time
-of writing, it is in the `sid` repositories).
-
-## Is Negroni a Framework?
-
-Negroni is **not** a framework. It is a middleware-focused library that is
-designed to work directly with `net/http`.
-
-## Routing?
-
-Negroni is BYOR (Bring your own Router). The Go community already has a number
-of great http routers available, and Negroni tries to play well with all of them
-by fully supporting `net/http`. For instance, integrating with [Gorilla Mux]
-looks like so:
-
-``` go
-router := mux.NewRouter()
-router.HandleFunc("/", HomeHandler)
-
-n := negroni.New(Middleware1, Middleware2)
-// Or use a middleware with the Use() function
-n.Use(Middleware3)
-// router goes last
-n.UseHandler(router)
-
-http.ListenAndServe(":3001", n)
-```
-
-## `negroni.Classic()`
-
-`negroni.Classic()` provides some default middleware that is useful for most
-applications:
-
-* [`negroni.Recovery`](#recovery) - Panic Recovery Middleware.
-* [`negroni.Logger`](#logger) - Request/Response Logger Middleware.
-* [`negroni.Static`](#static) - Static File serving under the "public"
- directory.
-
-This makes it really easy to get started with some useful features from Negroni.
-
-## Handlers
-
-Negroni provides a bidirectional middleware flow. This is done through the
-`negroni.Handler` interface:
-
-``` go
-type Handler interface {
- ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc)
-}
-```
-
-If a middleware hasn't already written to the `ResponseWriter`, it should call
-the next `http.HandlerFunc` in the chain to yield to the next middleware
-handler. This can be used for great good:
-
-``` go
-func MyMiddleware(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
- // do some stuff before
- next(rw, r)
- // do some stuff after
-}
-```
-
-And you can map it to the handler chain with the `Use` function:
-
-``` go
-n := negroni.New()
-n.Use(negroni.HandlerFunc(MyMiddleware))
-```
-
-You can also map plain old `http.Handler`s:
-
-``` go
-n := negroni.New()
-
-mux := http.NewServeMux()
-// map your routes
-
-n.UseHandler(mux)
-
-http.ListenAndServe(":3000", n)
-```
-
-## `With()`
-
-Negroni has a convenience function called `With`. `With` takes one or more
-`Handler` instances and returns a new `Negroni` with the combination of the
-receiver's handlers and the new handlers.
-
-```go
-// middleware we want to reuse
-common := negroni.New()
-common.Use(MyMiddleware1)
-common.Use(MyMiddleware2)
-
-// `specific` is a new negroni with the handlers from `common` combined with the
-// the handlers passed in
-specific := common.With(
- SpecificMiddleware1,
- SpecificMiddleware2
-)
-```
-
-## `Run()`
-
-Negroni has a convenience function called `Run`. `Run` takes an addr string
-identical to [`http.ListenAndServe`](https://godoc.org/net/http#ListenAndServe).
-
-
-``` go
-package main
-
-import (
- "github.com/urfave/negroni"
-)
-
-func main() {
- n := negroni.Classic()
- n.Run(":8080")
-}
-```
-If no address is provided, the `PORT` environment variable is used instead.
-If the `PORT` environment variable is not defined, the default address will be used.
-See [Run](https://godoc.org/github.com/urfave/negroni#Negroni.Run) for a complete description.
-
-In general, you will want to use `net/http` methods and pass `negroni` as a
-`Handler`, as this is more flexible, e.g.:
-
-
-``` go
-package main
-
-import (
- "fmt"
- "log"
- "net/http"
- "time"
-
- "github.com/urfave/negroni"
-)
-
-func main() {
- mux := http.NewServeMux()
- mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
- fmt.Fprintf(w, "Welcome to the home page!")
- })
-
- n := negroni.Classic() // Includes some default middlewares
- n.UseHandler(mux)
-
- s := &http.Server{
- Addr: ":8080",
- Handler: n,
- ReadTimeout: 10 * time.Second,
- WriteTimeout: 10 * time.Second,
- MaxHeaderBytes: 1 << 20,
- }
- log.Fatal(s.ListenAndServe())
-}
-```
-
-## Route Specific Middleware
-
-If you have a route group of routes that need specific middleware to be
-executed, you can simply create a new Negroni instance and use it as your route
-handler.
-
-``` go
-router := mux.NewRouter()
-adminRoutes := mux.NewRouter()
-// add admin routes here
-
-// Create a new negroni for the admin middleware
-router.PathPrefix("/admin").Handler(negroni.New(
- Middleware1,
- Middleware2,
- negroni.Wrap(adminRoutes),
-))
-```
-
-If you are using [Gorilla Mux], here is an example using a subrouter:
-
-``` go
-router := mux.NewRouter()
-subRouter := mux.NewRouter().PathPrefix("/subpath").Subrouter().StrictSlash(true)
-subRouter.HandleFunc("/", someSubpathHandler) // "/subpath/"
-subRouter.HandleFunc("/:id", someSubpathHandler) // "/subpath/:id"
-
-// "/subpath" is necessary to ensure the subRouter and main router linkup
-router.PathPrefix("/subpath").Handler(negroni.New(
- Middleware1,
- Middleware2,
- negroni.Wrap(subRouter),
-))
-```
-
-`With()` can be used to eliminate redundancy for middlewares shared across
-routes.
-
-``` go
-router := mux.NewRouter()
-apiRoutes := mux.NewRouter()
-// add api routes here
-webRoutes := mux.NewRouter()
-// add web routes here
-
-// create common middleware to be shared across routes
-common := negroni.New(
- Middleware1,
- Middleware2,
-)
-
-// create a new negroni for the api middleware
-// using the common middleware as a base
-router.PathPrefix("/api").Handler(common.With(
- APIMiddleware1,
- negroni.Wrap(apiRoutes),
-))
-// create a new negroni for the web middleware
-// using the common middleware as a base
-router.PathPrefix("/web").Handler(common.With(
- WebMiddleware1,
- negroni.Wrap(webRoutes),
-))
-```
-
-## Bundled Middleware
-
-### Static
-
-This middleware will serve files on the filesystem. If the files do not exist,
-it proxies the request to the next middleware. If you want the requests for
-non-existent files to return a `404 File Not Found` to the user you should look
-at using [http.FileServer](https://golang.org/pkg/net/http/#FileServer) as
-a handler.
-
-Example:
-
-
-``` go
-package main
-
-import (
- "fmt"
- "net/http"
-
- "github.com/urfave/negroni"
-)
-
-func main() {
- mux := http.NewServeMux()
- mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
- fmt.Fprintf(w, "Welcome to the home page!")
- })
-
- // Example of using a http.FileServer if you want "server-like" rather than "middleware" behavior
- // mux.Handle("/public", http.FileServer(http.Dir("/home/public")))
-
- n := negroni.New()
- n.Use(negroni.NewStatic(http.Dir("/tmp")))
- n.UseHandler(mux)
-
- http.ListenAndServe(":3002", n)
-}
-```
-
-Will serve files from the `/tmp` directory first, but proxy calls to the next
-handler if the request does not match a file on the filesystem.
-
-### Recovery
-
-This middleware catches `panic`s and responds with a `500` response code. If
-any other middleware has written a response code or body, this middleware will
-fail to properly send a 500 to the client, as the client has already received
-the HTTP response code. Additionally, an `ErrorHandlerFunc` can be attached
-to report 500's to an error reporting service such as Sentry or Airbrake.
-
-Example:
-
-
-``` go
-package main
-
-import (
- "net/http"
-
- "github.com/urfave/negroni"
-)
-
-func main() {
- mux := http.NewServeMux()
- mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
- panic("oh no")
- })
-
- n := negroni.New()
- n.Use(negroni.NewRecovery())
- n.UseHandler(mux)
-
- http.ListenAndServe(":3003", n)
-}
-```
-
-Will return a `500 Internal Server Error` to each request. It will also log the
-stack traces as well as print the stack trace to the requester if `PrintStack`
-is set to `true` (the default).
-
-Example with error handler:
-
-``` go
-package main
-
-import (
- "net/http"
-
- "github.com/urfave/negroni"
-)
-
-func main() {
- mux := http.NewServeMux()
- mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
- panic("oh no")
- })
-
- n := negroni.New()
- recovery := negroni.NewRecovery()
- recovery.ErrorHandlerFunc = reportToSentry
- n.Use(recovery)
- n.UseHandler(mux)
-
- http.ListenAndServe(":3003", n)
-}
-
-func reportToSentry(error interface{}) {
- // write code here to report error to Sentry
-}
-```
-
-The middleware simply output the informations on STDOUT by default.
-You can customize the output process by using the `SetFormatter()` function.
-
-You can use also the `HTMLPanicFormatter` to display a pretty HTML when a crash occurs.
-
-
-``` go
-package main
-
-import (
- "net/http"
-
- "github.com/urfave/negroni"
-)
-
-func main() {
- mux := http.NewServeMux()
- mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
- panic("oh no")
- })
-
- n := negroni.New()
- recovery := negroni.NewRecovery()
- recovery.Formatter = &negroni.HTMLPanicFormatter{}
- n.Use(recovery)
- n.UseHandler(mux)
-
- http.ListenAndServe(":3003", n)
-}
-```
-
-## Logger
-
-This middleware logs each incoming request and response.
-
-Example:
-
-
-``` go
-package main
-
-import (
- "fmt"
- "net/http"
-
- "github.com/urfave/negroni"
-)
-
-func main() {
- mux := http.NewServeMux()
- mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
- fmt.Fprintf(w, "Welcome to the home page!")
- })
-
- n := negroni.New()
- n.Use(negroni.NewLogger())
- n.UseHandler(mux)
-
- http.ListenAndServe(":3004", n)
-}
-```
-
-Will print a log similar to:
-
-```
-[negroni] 2017-10-04T14:56:25+02:00 | 200 | 378µs | localhost:3004 | GET /
-```
-
-on each request.
-
-You can also set your own log format by calling the `SetFormat` function. The format is a template string with fields as mentioned in the `LoggerEntry` struct. So, as an example -
-
-```go
-l.SetFormat("[{{.Status}} {{.Duration}}] - {{.Request.UserAgent}}")
-```
-
-will show something like - `[200 18.263µs] - Go-User-Agent/1.1 `
-
-## Third Party Middleware
-
-Here is a current list of Negroni compatible middlware. Feel free to put up a PR
-linking your middleware if you have built one:
-
-| Middleware | Author | Description |
-| -----------|--------|-------------|
-| [authz](https://github.com/casbin/negroni-authz) | [Yang Luo](https://github.com/hsluoyz) | ACL, RBAC, ABAC Authorization middlware based on [Casbin](https://github.com/casbin/casbin) |
-| [binding](https://github.com/mholt/binding) | [Matt Holt](https://github.com/mholt) | Data binding from HTTP requests into structs |
-| [cloudwatch](https://github.com/cvillecsteele/negroni-cloudwatch) | [Colin Steele](https://github.com/cvillecsteele) | AWS cloudwatch metrics middleware |
-| [cors](https://github.com/rs/cors) | [Olivier Poitrey](https://github.com/rs) | [Cross Origin Resource Sharing](http://www.w3.org/TR/cors/) (CORS) support |
-| [csp](https://github.com/awakenetworks/csp) | [Awake Networks](https://github.com/awakenetworks) | [Content Security Policy](https://www.w3.org/TR/CSP2/) (CSP) support |
-| [delay](https://github.com/jeffbmartinez/delay) | [Jeff Martinez](https://github.com/jeffbmartinez) | Add delays/latency to endpoints. Useful when testing effects of high latency |
-| [New Relic Go Agent](https://github.com/yadvendar/negroni-newrelic-go-agent) | [Yadvendar Champawat](https://github.com/yadvendar) | Official [New Relic Go Agent](https://github.com/newrelic/go-agent) (currently in beta) |
-| [gorelic](https://github.com/jingweno/negroni-gorelic) | [Jingwen Owen Ou](https://github.com/jingweno) | New Relic agent for Go runtime |
-| [Graceful](https://github.com/tylerb/graceful) | [Tyler Bunnell](https://github.com/tylerb) | Graceful HTTP Shutdown |
-| [gzip](https://github.com/phyber/negroni-gzip) | [phyber](https://github.com/phyber) | GZIP response compression |
-| [JWT Middleware](https://github.com/auth0/go-jwt-middleware) | [Auth0](https://github.com/auth0) | Middleware checks for a JWT on the `Authorization` header on incoming requests and decodes it|
-| [logrus](https://github.com/meatballhat/negroni-logrus) | [Dan Buch](https://github.com/meatballhat) | Logrus-based logger |
-| [oauth2](https://github.com/goincremental/negroni-oauth2) | [David Bochenski](https://github.com/bochenski) | oAuth2 middleware |
-| [onthefly](https://github.com/xyproto/onthefly) | [Alexander Rødseth](https://github.com/xyproto) | Generate TinySVG, HTML and CSS on the fly |
-| [permissions2](https://github.com/xyproto/permissions2) | [Alexander Rødseth](https://github.com/xyproto) | Cookies, users and permissions |
-| [prometheus](https://github.com/zbindenren/negroni-prometheus) | [Rene Zbinden](https://github.com/zbindenren) | Easily create metrics endpoint for the [prometheus](http://prometheus.io) instrumentation tool |
-| [render](https://github.com/unrolled/render) | [Cory Jacobsen](https://github.com/unrolled) | Render JSON, XML and HTML templates |
-| [RestGate](https://github.com/pjebs/restgate) | [Prasanga Siripala](https://github.com/pjebs) | Secure authentication for REST API endpoints |
-| [secure](https://github.com/unrolled/secure) | [Cory Jacobsen](https://github.com/unrolled) | Middleware that implements a few quick security wins |
-| [sessions](https://github.com/goincremental/negroni-sessions) | [David Bochenski](https://github.com/bochenski) | Session Management |
-| [stats](https://github.com/thoas/stats) | [Florent Messa](https://github.com/thoas) | Store information about your web application (response time, etc.) |
-| [VanGoH](https://github.com/auroratechnologies/vangoh) | [Taylor Wrobel](https://github.com/twrobel3) | Configurable [AWS-Style](http://docs.aws.amazon.com/AmazonS3/latest/dev/RESTAuthentication.html) HMAC authentication middleware |
-| [xrequestid](https://github.com/pilu/xrequestid) | [Andrea Franz](https://github.com/pilu) | Middleware that assigns a random X-Request-Id header to each request |
-| [mgo session](https://github.com/joeljames/nigroni-mgo-session) | [Joel James](https://github.com/joeljames) | Middleware that handles creating and closing mgo sessions per request |
-| [digits](https://github.com/bamarni/digits) | [Bilal Amarni](https://github.com/bamarni) | Middleware that handles [Twitter Digits](https://get.digits.com/) authentication |
-
-## Examples
-
-[Alexander Rødseth](https://github.com/xyproto) created
-[mooseware](https://github.com/xyproto/mooseware), a skeleton for writing a
-Negroni middleware handler.
-
-[Prasanga Siripala](https://github.com/pjebs) created an effective skeleton structure for web-based Go/Negroni projects: [Go-Skeleton](https://github.com/pjebs/go-skeleton)
-
-## Live code reload?
-
-[gin](https://github.com/codegangsta/gin) and
-[fresh](https://github.com/pilu/fresh) both live reload negroni apps.
-
-## Essential Reading for Beginners of Go & Negroni
-
-* [Using a Context to pass information from middleware to end handler](http://elithrar.github.io/article/map-string-interface/)
-* [Understanding middleware](https://mattstauffer.co/blog/laravel-5.0-middleware-filter-style)
-
-## About
-
-Negroni is obsessively designed by none other than the [Code
-Gangsta](https://codegangsta.io/)
-
-[Gorilla Mux]: https://github.com/gorilla/mux
-[`http.FileSystem`]: https://godoc.org/net/http#FileSystem
diff --git a/vendor/github.com/codegangsta/negroni/doc.go b/vendor/github.com/codegangsta/negroni/doc.go
deleted file mode 100644
index add1ed9..0000000
--- a/vendor/github.com/codegangsta/negroni/doc.go
+++ /dev/null
@@ -1,25 +0,0 @@
-// Package negroni is an idiomatic approach to web middleware in Go. It is tiny, non-intrusive, and encourages use of net/http Handlers.
-//
-// If you like the idea of Martini, but you think it contains too much magic, then Negroni is a great fit.
-//
-// For a full guide visit http://github.com/urfave/negroni
-//
-// package main
-//
-// import (
-// "github.com/urfave/negroni"
-// "net/http"
-// "fmt"
-// )
-//
-// func main() {
-// mux := http.NewServeMux()
-// mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
-// fmt.Fprintf(w, "Welcome to the home page!")
-// })
-//
-// n := negroni.Classic()
-// n.UseHandler(mux)
-// n.Run(":3000")
-// }
-package negroni
diff --git a/vendor/github.com/codegangsta/negroni/logger.go b/vendor/github.com/codegangsta/negroni/logger.go
deleted file mode 100644
index 5bf7731..0000000
--- a/vendor/github.com/codegangsta/negroni/logger.go
+++ /dev/null
@@ -1,82 +0,0 @@
-package negroni
-
-import (
- "bytes"
-
- "log"
- "net/http"
- "os"
- "text/template"
- "time"
-)
-
-// LoggerEntry is the structure
-// passed to the template.
-type LoggerEntry struct {
- StartTime string
- Status int
- Duration time.Duration
- Hostname string
- Method string
- Path string
- Request *http.Request
-}
-
-// LoggerDefaultFormat is the format
-// logged used by the default Logger instance.
-var LoggerDefaultFormat = "{{.StartTime}} | {{.Status}} | \t {{.Duration}} | {{.Hostname}} | {{.Method}} {{.Path}} \n"
-
-// LoggerDefaultDateFormat is the
-// format used for date by the
-// default Logger instance.
-var LoggerDefaultDateFormat = time.RFC3339
-
-// ALogger interface
-type ALogger interface {
- Println(v ...interface{})
- Printf(format string, v ...interface{})
-}
-
-// Logger is a middleware handler that logs the request as it goes in and the response as it goes out.
-type Logger struct {
- // ALogger implements just enough log.Logger interface to be compatible with other implementations
- ALogger
- dateFormat string
- template *template.Template
-}
-
-// NewLogger returns a new Logger instance
-func NewLogger() *Logger {
- logger := &Logger{ALogger: log.New(os.Stdout, "[negroni] ", 0), dateFormat: LoggerDefaultDateFormat}
- logger.SetFormat(LoggerDefaultFormat)
- return logger
-}
-
-func (l *Logger) SetFormat(format string) {
- l.template = template.Must(template.New("negroni_parser").Parse(format))
-}
-
-func (l *Logger) SetDateFormat(format string) {
- l.dateFormat = format
-}
-
-func (l *Logger) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
- start := time.Now()
-
- next(rw, r)
-
- res := rw.(ResponseWriter)
- log := LoggerEntry{
- StartTime: start.Format(l.dateFormat),
- Status: res.Status(),
- Duration: time.Since(start),
- Hostname: r.Host,
- Method: r.Method,
- Path: r.URL.Path,
- Request: r,
- }
-
- buff := &bytes.Buffer{}
- l.template.Execute(buff, log)
- l.Printf(buff.String())
-}
diff --git a/vendor/github.com/codegangsta/negroni/negroni.go b/vendor/github.com/codegangsta/negroni/negroni.go
deleted file mode 100644
index d1d7782..0000000
--- a/vendor/github.com/codegangsta/negroni/negroni.go
+++ /dev/null
@@ -1,169 +0,0 @@
-package negroni
-
-import (
- "log"
- "net/http"
- "os"
-)
-
-const (
- // DefaultAddress is used if no other is specified.
- DefaultAddress = ":8080"
-)
-
-// Handler handler is an interface that objects can implement to be registered to serve as middleware
-// in the Negroni middleware stack.
-// ServeHTTP should yield to the next middleware in the chain by invoking the next http.HandlerFunc
-// passed in.
-//
-// If the Handler writes to the ResponseWriter, the next http.HandlerFunc should not be invoked.
-type Handler interface {
- ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc)
-}
-
-// HandlerFunc is an adapter to allow the use of ordinary functions as Negroni handlers.
-// If f is a function with the appropriate signature, HandlerFunc(f) is a Handler object that calls f.
-type HandlerFunc func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc)
-
-func (h HandlerFunc) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
- h(rw, r, next)
-}
-
-type middleware struct {
- handler Handler
- next *middleware
-}
-
-func (m middleware) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
- m.handler.ServeHTTP(rw, r, m.next.ServeHTTP)
-}
-
-// Wrap converts a http.Handler into a negroni.Handler so it can be used as a Negroni
-// middleware. The next http.HandlerFunc is automatically called after the Handler
-// is executed.
-func Wrap(handler http.Handler) Handler {
- return HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
- handler.ServeHTTP(rw, r)
- next(rw, r)
- })
-}
-
-// WrapFunc converts a http.HandlerFunc into a negroni.Handler so it can be used as a Negroni
-// middleware. The next http.HandlerFunc is automatically called after the Handler
-// is executed.
-func WrapFunc(handlerFunc http.HandlerFunc) Handler {
- return HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
- handlerFunc(rw, r)
- next(rw, r)
- })
-}
-
-// Negroni is a stack of Middleware Handlers that can be invoked as an http.Handler.
-// Negroni middleware is evaluated in the order that they are added to the stack using
-// the Use and UseHandler methods.
-type Negroni struct {
- middleware middleware
- handlers []Handler
-}
-
-// New returns a new Negroni instance with no middleware preconfigured.
-func New(handlers ...Handler) *Negroni {
- return &Negroni{
- handlers: handlers,
- middleware: build(handlers),
- }
-}
-
-// With returns a new Negroni instance that is a combination of the negroni
-// receiver's handlers and the provided handlers.
-func (n *Negroni) With(handlers ...Handler) *Negroni {
- return New(
- append(n.handlers, handlers...)...,
- )
-}
-
-// Classic returns a new Negroni instance with the default middleware already
-// in the stack.
-//
-// Recovery - Panic Recovery Middleware
-// Logger - Request/Response Logging
-// Static - Static File Serving
-func Classic() *Negroni {
- return New(NewRecovery(), NewLogger(), NewStatic(http.Dir("public")))
-}
-
-func (n *Negroni) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
- n.middleware.ServeHTTP(NewResponseWriter(rw), r)
-}
-
-// Use adds a Handler onto the middleware stack. Handlers are invoked in the order they are added to a Negroni.
-func (n *Negroni) Use(handler Handler) {
- if handler == nil {
- panic("handler cannot be nil")
- }
-
- n.handlers = append(n.handlers, handler)
- n.middleware = build(n.handlers)
-}
-
-// UseFunc adds a Negroni-style handler function onto the middleware stack.
-func (n *Negroni) UseFunc(handlerFunc func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc)) {
- n.Use(HandlerFunc(handlerFunc))
-}
-
-// UseHandler adds a http.Handler onto the middleware stack. Handlers are invoked in the order they are added to a Negroni.
-func (n *Negroni) UseHandler(handler http.Handler) {
- n.Use(Wrap(handler))
-}
-
-// UseHandlerFunc adds a http.HandlerFunc-style handler function onto the middleware stack.
-func (n *Negroni) UseHandlerFunc(handlerFunc func(rw http.ResponseWriter, r *http.Request)) {
- n.UseHandler(http.HandlerFunc(handlerFunc))
-}
-
-// Run is a convenience function that runs the negroni stack as an HTTP
-// server. The addr string, if provided, takes the same format as http.ListenAndServe.
-// If no address is provided but the PORT environment variable is set, the PORT value is used.
-// If neither is provided, the address' value will equal the DefaultAddress constant.
-func (n *Negroni) Run(addr ...string) {
- l := log.New(os.Stdout, "[negroni] ", 0)
- finalAddr := detectAddress(addr...)
- l.Printf("listening on %s", finalAddr)
- l.Fatal(http.ListenAndServe(finalAddr, n))
-}
-
-func detectAddress(addr ...string) string {
- if len(addr) > 0 {
- return addr[0]
- }
- if port := os.Getenv("PORT"); port != "" {
- return ":" + port
- }
- return DefaultAddress
-}
-
-// Returns a list of all the handlers in the current Negroni middleware chain.
-func (n *Negroni) Handlers() []Handler {
- return n.handlers
-}
-
-func build(handlers []Handler) middleware {
- var next middleware
-
- if len(handlers) == 0 {
- return voidMiddleware()
- } else if len(handlers) > 1 {
- next = build(handlers[1:])
- } else {
- next = voidMiddleware()
- }
-
- return middleware{handlers[0], &next}
-}
-
-func voidMiddleware() middleware {
- return middleware{
- HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {}),
- &middleware{},
- }
-}
diff --git a/vendor/github.com/codegangsta/negroni/recovery.go b/vendor/github.com/codegangsta/negroni/recovery.go
deleted file mode 100644
index 1a6570e..0000000
--- a/vendor/github.com/codegangsta/negroni/recovery.go
+++ /dev/null
@@ -1,179 +0,0 @@
-package negroni
-
-import (
- "fmt"
- "log"
- "net/http"
- "os"
- "runtime"
- "runtime/debug"
- "text/template"
-)
-
-const (
- panicText = "PANIC: %s\n%s"
- panicHTML = `
-PANIC: {{.RecoveredPanic}}
-
-
-
Negroni - PANIC
-
-
-
{{.RequestDescription}}
- Runtime error:{{.RecoveredPanic}}
-
-
-{{ if .Stack }}
-
-
Runtime Stack
-
{{.StackAsString}}
-
-{{ end }}
-
-
-`
- nilRequestMessage = "Request is nil"
-)
-
-var panicHTMLTemplate = template.Must(template.New("PanicPage").Parse(panicHTML))
-
-// PanicInformation contains all
-// elements for printing stack informations.
-type PanicInformation struct {
- RecoveredPanic interface{}
- Stack []byte
- Request *http.Request
-}
-
-// StackAsString returns a printable version of the stack
-func (p *PanicInformation) StackAsString() string {
- return string(p.Stack)
-}
-
-// RequestDescription returns a printable description of the url
-func (p *PanicInformation) RequestDescription() string {
-
- if p.Request == nil {
- return nilRequestMessage
- }
-
- var queryOutput string
- if p.Request.URL.RawQuery != "" {
- queryOutput = "?" + p.Request.URL.RawQuery
- }
- return fmt.Sprintf("%s %s%s", p.Request.Method, p.Request.URL.Path, queryOutput)
-}
-
-// PanicFormatter is an interface on object can implement
-// to be able to output the stack trace
-type PanicFormatter interface {
- // FormatPanicError output the stack for a given answer/response.
- // In case the the middleware should not output the stack trace,
- // the field `Stack` of the passed `PanicInformation` instance equals `[]byte{}`.
- FormatPanicError(rw http.ResponseWriter, r *http.Request, infos *PanicInformation)
-}
-
-// TextPanicFormatter output the stack
-// as simple text on os.Stdout. If no `Content-Type` is set,
-// it will output the data as `text/plain; charset=utf-8`.
-// Otherwise, the origin `Content-Type` is kept.
-type TextPanicFormatter struct{}
-
-func (t *TextPanicFormatter) FormatPanicError(rw http.ResponseWriter, r *http.Request, infos *PanicInformation) {
- if rw.Header().Get("Content-Type") == "" {
- rw.Header().Set("Content-Type", "text/plain; charset=utf-8")
- }
- fmt.Fprintf(rw, panicText, infos.RecoveredPanic, infos.Stack)
-}
-
-// HTMLPanicFormatter output the stack inside
-// an HTML page. This has been largely inspired by
-// https://github.com/go-martini/martini/pull/156/commits.
-type HTMLPanicFormatter struct{}
-
-func (t *HTMLPanicFormatter) FormatPanicError(rw http.ResponseWriter, r *http.Request, infos *PanicInformation) {
- if rw.Header().Get("Content-Type") == "" {
- rw.Header().Set("Content-Type", "text/html; charset=utf-8")
- }
- panicHTMLTemplate.Execute(rw, infos)
-}
-
-// Recovery is a Negroni middleware that recovers from any panics and writes a 500 if there was one.
-type Recovery struct {
- Logger ALogger
- PrintStack bool
- ErrorHandlerFunc func(interface{})
- StackAll bool
- StackSize int
- Formatter PanicFormatter
-}
-
-// NewRecovery returns a new instance of Recovery
-func NewRecovery() *Recovery {
- return &Recovery{
- Logger: log.New(os.Stdout, "[negroni] ", 0),
- PrintStack: true,
- StackAll: false,
- StackSize: 1024 * 8,
- Formatter: &TextPanicFormatter{},
- }
-}
-
-func (rec *Recovery) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
- defer func() {
- if err := recover(); err != nil {
- rw.WriteHeader(http.StatusInternalServerError)
-
- stack := make([]byte, rec.StackSize)
- stack = stack[:runtime.Stack(stack, rec.StackAll)]
- infos := &PanicInformation{RecoveredPanic: err, Request: r}
-
- if rec.PrintStack {
- infos.Stack = stack
- }
- rec.Logger.Printf(panicText, err, stack)
- rec.Formatter.FormatPanicError(rw, r, infos)
-
- if rec.ErrorHandlerFunc != nil {
- func() {
- defer func() {
- if err := recover(); err != nil {
- rec.Logger.Printf("provided ErrorHandlerFunc panic'd: %s, trace:\n%s", err, debug.Stack())
- rec.Logger.Printf("%s\n", debug.Stack())
- }
- }()
- rec.ErrorHandlerFunc(err)
- }()
- }
- }
- }()
-
- next(rw, r)
-}
diff --git a/vendor/github.com/codegangsta/negroni/response_writer.go b/vendor/github.com/codegangsta/negroni/response_writer.go
deleted file mode 100644
index cc507eb..0000000
--- a/vendor/github.com/codegangsta/negroni/response_writer.go
+++ /dev/null
@@ -1,113 +0,0 @@
-package negroni
-
-import (
- "bufio"
- "fmt"
- "net"
- "net/http"
-)
-
-// ResponseWriter is a wrapper around http.ResponseWriter that provides extra information about
-// the response. It is recommended that middleware handlers use this construct to wrap a responsewriter
-// if the functionality calls for it.
-type ResponseWriter interface {
- http.ResponseWriter
- http.Flusher
- // Status returns the status code of the response or 0 if the response has
- // not been written
- Status() int
- // Written returns whether or not the ResponseWriter has been written.
- Written() bool
- // Size returns the size of the response body.
- Size() int
- // Before allows for a function to be called before the ResponseWriter has been written to. This is
- // useful for setting headers or any other operations that must happen before a response has been written.
- Before(func(ResponseWriter))
-}
-
-type beforeFunc func(ResponseWriter)
-
-// NewResponseWriter creates a ResponseWriter that wraps an http.ResponseWriter
-func NewResponseWriter(rw http.ResponseWriter) ResponseWriter {
- nrw := &responseWriter{
- ResponseWriter: rw,
- }
-
- if _, ok := rw.(http.CloseNotifier); ok {
- return &responseWriterCloseNotifer{nrw}
- }
-
- return nrw
-}
-
-type responseWriter struct {
- http.ResponseWriter
- status int
- size int
- beforeFuncs []beforeFunc
-}
-
-func (rw *responseWriter) WriteHeader(s int) {
- rw.status = s
- rw.callBefore()
- rw.ResponseWriter.WriteHeader(s)
-}
-
-func (rw *responseWriter) Write(b []byte) (int, error) {
- if !rw.Written() {
- // The status will be StatusOK if WriteHeader has not been called yet
- rw.WriteHeader(http.StatusOK)
- }
- size, err := rw.ResponseWriter.Write(b)
- rw.size += size
- return size, err
-}
-
-func (rw *responseWriter) Status() int {
- return rw.status
-}
-
-func (rw *responseWriter) Size() int {
- return rw.size
-}
-
-func (rw *responseWriter) Written() bool {
- return rw.status != 0
-}
-
-func (rw *responseWriter) Before(before func(ResponseWriter)) {
- rw.beforeFuncs = append(rw.beforeFuncs, before)
-}
-
-func (rw *responseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
- hijacker, ok := rw.ResponseWriter.(http.Hijacker)
- if !ok {
- return nil, nil, fmt.Errorf("the ResponseWriter doesn't support the Hijacker interface")
- }
- return hijacker.Hijack()
-}
-
-func (rw *responseWriter) callBefore() {
- for i := len(rw.beforeFuncs) - 1; i >= 0; i-- {
- rw.beforeFuncs[i](rw)
- }
-}
-
-func (rw *responseWriter) Flush() {
- flusher, ok := rw.ResponseWriter.(http.Flusher)
- if ok {
- if !rw.Written() {
- // The status will be StatusOK if WriteHeader has not been called yet
- rw.WriteHeader(http.StatusOK)
- }
- flusher.Flush()
- }
-}
-
-type responseWriterCloseNotifer struct {
- *responseWriter
-}
-
-func (rw *responseWriterCloseNotifer) CloseNotify() <-chan bool {
- return rw.ResponseWriter.(http.CloseNotifier).CloseNotify()
-}
diff --git a/vendor/github.com/codegangsta/negroni/response_writer_pusher.go b/vendor/github.com/codegangsta/negroni/response_writer_pusher.go
deleted file mode 100644
index 213cb35..0000000
--- a/vendor/github.com/codegangsta/negroni/response_writer_pusher.go
+++ /dev/null
@@ -1,16 +0,0 @@
-//+build go1.8
-
-package negroni
-
-import (
- "fmt"
- "net/http"
-)
-
-func (rw *responseWriter) Push(target string, opts *http.PushOptions) error {
- pusher, ok := rw.ResponseWriter.(http.Pusher)
- if ok {
- return pusher.Push(target, opts)
- }
- return fmt.Errorf("the ResponseWriter doesn't support the Pusher interface")
-}
diff --git a/vendor/github.com/codegangsta/negroni/static.go b/vendor/github.com/codegangsta/negroni/static.go
deleted file mode 100644
index 34be967..0000000
--- a/vendor/github.com/codegangsta/negroni/static.go
+++ /dev/null
@@ -1,88 +0,0 @@
-package negroni
-
-import (
- "net/http"
- "path"
- "strings"
-)
-
-// Static is a middleware handler that serves static files in the given
-// directory/filesystem. If the file does not exist on the filesystem, it
-// passes along to the next middleware in the chain. If you desire "fileserver"
-// type behavior where it returns a 404 for unfound files, you should consider
-// using http.FileServer from the Go stdlib.
-type Static struct {
- // Dir is the directory to serve static files from
- Dir http.FileSystem
- // Prefix is the optional prefix used to serve the static directory content
- Prefix string
- // IndexFile defines which file to serve as index if it exists.
- IndexFile string
-}
-
-// NewStatic returns a new instance of Static
-func NewStatic(directory http.FileSystem) *Static {
- return &Static{
- Dir: directory,
- Prefix: "",
- IndexFile: "index.html",
- }
-}
-
-func (s *Static) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
- if r.Method != "GET" && r.Method != "HEAD" {
- next(rw, r)
- return
- }
- file := r.URL.Path
- // if we have a prefix, filter requests by stripping the prefix
- if s.Prefix != "" {
- if !strings.HasPrefix(file, s.Prefix) {
- next(rw, r)
- return
- }
- file = file[len(s.Prefix):]
- if file != "" && file[0] != '/' {
- next(rw, r)
- return
- }
- }
- f, err := s.Dir.Open(file)
- if err != nil {
- // discard the error?
- next(rw, r)
- return
- }
- defer f.Close()
-
- fi, err := f.Stat()
- if err != nil {
- next(rw, r)
- return
- }
-
- // try to serve index file
- if fi.IsDir() {
- // redirect if missing trailing slash
- if !strings.HasSuffix(r.URL.Path, "/") {
- http.Redirect(rw, r, r.URL.Path+"/", http.StatusFound)
- return
- }
-
- file = path.Join(file, s.IndexFile)
- f, err = s.Dir.Open(file)
- if err != nil {
- next(rw, r)
- return
- }
- defer f.Close()
-
- fi, err = f.Stat()
- if err != nil || fi.IsDir() {
- next(rw, r)
- return
- }
- }
-
- http.ServeContent(rw, r, file, fi.ModTime(), f)
-}
diff --git a/vendor/github.com/dustin/go-humanize/.travis.yml b/vendor/github.com/dustin/go-humanize/.travis.yml
new file mode 100644
index 0000000..ba95cdd
--- /dev/null
+++ b/vendor/github.com/dustin/go-humanize/.travis.yml
@@ -0,0 +1,21 @@
+sudo: false
+language: go
+go:
+ - 1.3.x
+ - 1.5.x
+ - 1.6.x
+ - 1.7.x
+ - 1.8.x
+ - 1.9.x
+ - master
+matrix:
+ allow_failures:
+ - go: master
+ fast_finish: true
+install:
+ - # Do nothing. This is needed to prevent default install action "go get -t -v ./..." from happening here (we want it to happen inside script step).
+script:
+ - go get -t -v ./...
+ - diff -u <(echo -n) <(gofmt -d -s .)
+ - go tool vet .
+ - go test -v -race ./...
diff --git a/vendor/github.com/codegangsta/negroni/LICENSE b/vendor/github.com/dustin/go-humanize/LICENSE
similarity index 84%
rename from vendor/github.com/codegangsta/negroni/LICENSE
rename to vendor/github.com/dustin/go-humanize/LICENSE
index 08b5e20..8d9a94a 100644
--- a/vendor/github.com/codegangsta/negroni/LICENSE
+++ b/vendor/github.com/dustin/go-humanize/LICENSE
@@ -1,6 +1,4 @@
-The MIT License (MIT)
-
-Copyright (c) 2014 Jeremy Saenz
+Copyright (c) 2005-2008 Dustin Sallings
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@@ -9,8 +7,8 @@ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
@@ -19,3 +17,5 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+
+
diff --git a/vendor/github.com/dustin/go-humanize/README.markdown b/vendor/github.com/dustin/go-humanize/README.markdown
new file mode 100644
index 0000000..91b4ae5
--- /dev/null
+++ b/vendor/github.com/dustin/go-humanize/README.markdown
@@ -0,0 +1,124 @@
+# Humane Units [](https://travis-ci.org/dustin/go-humanize) [](https://godoc.org/github.com/dustin/go-humanize)
+
+Just a few functions for helping humanize times and sizes.
+
+`go get` it as `github.com/dustin/go-humanize`, import it as
+`"github.com/dustin/go-humanize"`, use it as `humanize`.
+
+See [godoc](https://godoc.org/github.com/dustin/go-humanize) for
+complete documentation.
+
+## Sizes
+
+This lets you take numbers like `82854982` and convert them to useful
+strings like, `83 MB` or `79 MiB` (whichever you prefer).
+
+Example:
+
+```go
+fmt.Printf("That file is %s.", humanize.Bytes(82854982)) // That file is 83 MB.
+```
+
+## Times
+
+This lets you take a `time.Time` and spit it out in relative terms.
+For example, `12 seconds ago` or `3 days from now`.
+
+Example:
+
+```go
+fmt.Printf("This was touched %s.", humanize.Time(someTimeInstance)) // This was touched 7 hours ago.
+```
+
+Thanks to Kyle Lemons for the time implementation from an IRC
+conversation one day. It's pretty neat.
+
+## Ordinals
+
+From a [mailing list discussion][odisc] where a user wanted to be able
+to label ordinals.
+
+ 0 -> 0th
+ 1 -> 1st
+ 2 -> 2nd
+ 3 -> 3rd
+ 4 -> 4th
+ [...]
+
+Example:
+
+```go
+fmt.Printf("You're my %s best friend.", humanize.Ordinal(193)) // You are my 193rd best friend.
+```
+
+## Commas
+
+Want to shove commas into numbers? Be my guest.
+
+ 0 -> 0
+ 100 -> 100
+ 1000 -> 1,000
+ 1000000000 -> 1,000,000,000
+ -100000 -> -100,000
+
+Example:
+
+```go
+fmt.Printf("You owe $%s.\n", humanize.Comma(6582491)) // You owe $6,582,491.
+```
+
+## Ftoa
+
+Nicer float64 formatter that removes trailing zeros.
+
+```go
+fmt.Printf("%f", 2.24) // 2.240000
+fmt.Printf("%s", humanize.Ftoa(2.24)) // 2.24
+fmt.Printf("%f", 2.0) // 2.000000
+fmt.Printf("%s", humanize.Ftoa(2.0)) // 2
+```
+
+## SI notation
+
+Format numbers with [SI notation][sinotation].
+
+Example:
+
+```go
+humanize.SI(0.00000000223, "M") // 2.23 nM
+```
+
+## English-specific functions
+
+The following functions are in the `humanize/english` subpackage.
+
+### Plurals
+
+Simple English pluralization
+
+```go
+english.PluralWord(1, "object", "") // object
+english.PluralWord(42, "object", "") // objects
+english.PluralWord(2, "bus", "") // buses
+english.PluralWord(99, "locus", "loci") // loci
+
+english.Plural(1, "object", "") // 1 object
+english.Plural(42, "object", "") // 42 objects
+english.Plural(2, "bus", "") // 2 buses
+english.Plural(99, "locus", "loci") // 99 loci
+```
+
+### Word series
+
+Format comma-separated words lists with conjuctions:
+
+```go
+english.WordSeries([]string{"foo"}, "and") // foo
+english.WordSeries([]string{"foo", "bar"}, "and") // foo and bar
+english.WordSeries([]string{"foo", "bar", "baz"}, "and") // foo, bar and baz
+
+english.OxfordWordSeries([]string{"foo", "bar", "baz"}, "and") // foo, bar, and baz
+```
+
+[odisc]: https://groups.google.com/d/topic/golang-nuts/l8NhI74jl-4/discussion
+[sinotation]: http://en.wikipedia.org/wiki/Metric_prefix
diff --git a/vendor/github.com/dustin/go-humanize/big.go b/vendor/github.com/dustin/go-humanize/big.go
new file mode 100644
index 0000000..f49dc33
--- /dev/null
+++ b/vendor/github.com/dustin/go-humanize/big.go
@@ -0,0 +1,31 @@
+package humanize
+
+import (
+ "math/big"
+)
+
+// order of magnitude (to a max order)
+func oomm(n, b *big.Int, maxmag int) (float64, int) {
+ mag := 0
+ m := &big.Int{}
+ for n.Cmp(b) >= 0 {
+ n.DivMod(n, b, m)
+ mag++
+ if mag == maxmag && maxmag >= 0 {
+ break
+ }
+ }
+ return float64(n.Int64()) + (float64(m.Int64()) / float64(b.Int64())), mag
+}
+
+// total order of magnitude
+// (same as above, but with no upper limit)
+func oom(n, b *big.Int) (float64, int) {
+ mag := 0
+ m := &big.Int{}
+ for n.Cmp(b) >= 0 {
+ n.DivMod(n, b, m)
+ mag++
+ }
+ return float64(n.Int64()) + (float64(m.Int64()) / float64(b.Int64())), mag
+}
diff --git a/vendor/github.com/dustin/go-humanize/bigbytes.go b/vendor/github.com/dustin/go-humanize/bigbytes.go
new file mode 100644
index 0000000..1a2bf61
--- /dev/null
+++ b/vendor/github.com/dustin/go-humanize/bigbytes.go
@@ -0,0 +1,173 @@
+package humanize
+
+import (
+ "fmt"
+ "math/big"
+ "strings"
+ "unicode"
+)
+
+var (
+ bigIECExp = big.NewInt(1024)
+
+ // BigByte is one byte in bit.Ints
+ BigByte = big.NewInt(1)
+ // BigKiByte is 1,024 bytes in bit.Ints
+ BigKiByte = (&big.Int{}).Mul(BigByte, bigIECExp)
+ // BigMiByte is 1,024 k bytes in bit.Ints
+ BigMiByte = (&big.Int{}).Mul(BigKiByte, bigIECExp)
+ // BigGiByte is 1,024 m bytes in bit.Ints
+ BigGiByte = (&big.Int{}).Mul(BigMiByte, bigIECExp)
+ // BigTiByte is 1,024 g bytes in bit.Ints
+ BigTiByte = (&big.Int{}).Mul(BigGiByte, bigIECExp)
+ // BigPiByte is 1,024 t bytes in bit.Ints
+ BigPiByte = (&big.Int{}).Mul(BigTiByte, bigIECExp)
+ // BigEiByte is 1,024 p bytes in bit.Ints
+ BigEiByte = (&big.Int{}).Mul(BigPiByte, bigIECExp)
+ // BigZiByte is 1,024 e bytes in bit.Ints
+ BigZiByte = (&big.Int{}).Mul(BigEiByte, bigIECExp)
+ // BigYiByte is 1,024 z bytes in bit.Ints
+ BigYiByte = (&big.Int{}).Mul(BigZiByte, bigIECExp)
+)
+
+var (
+ bigSIExp = big.NewInt(1000)
+
+ // BigSIByte is one SI byte in big.Ints
+ BigSIByte = big.NewInt(1)
+ // BigKByte is 1,000 SI bytes in big.Ints
+ BigKByte = (&big.Int{}).Mul(BigSIByte, bigSIExp)
+ // BigMByte is 1,000 SI k bytes in big.Ints
+ BigMByte = (&big.Int{}).Mul(BigKByte, bigSIExp)
+ // BigGByte is 1,000 SI m bytes in big.Ints
+ BigGByte = (&big.Int{}).Mul(BigMByte, bigSIExp)
+ // BigTByte is 1,000 SI g bytes in big.Ints
+ BigTByte = (&big.Int{}).Mul(BigGByte, bigSIExp)
+ // BigPByte is 1,000 SI t bytes in big.Ints
+ BigPByte = (&big.Int{}).Mul(BigTByte, bigSIExp)
+ // BigEByte is 1,000 SI p bytes in big.Ints
+ BigEByte = (&big.Int{}).Mul(BigPByte, bigSIExp)
+ // BigZByte is 1,000 SI e bytes in big.Ints
+ BigZByte = (&big.Int{}).Mul(BigEByte, bigSIExp)
+ // BigYByte is 1,000 SI z bytes in big.Ints
+ BigYByte = (&big.Int{}).Mul(BigZByte, bigSIExp)
+)
+
+var bigBytesSizeTable = map[string]*big.Int{
+ "b": BigByte,
+ "kib": BigKiByte,
+ "kb": BigKByte,
+ "mib": BigMiByte,
+ "mb": BigMByte,
+ "gib": BigGiByte,
+ "gb": BigGByte,
+ "tib": BigTiByte,
+ "tb": BigTByte,
+ "pib": BigPiByte,
+ "pb": BigPByte,
+ "eib": BigEiByte,
+ "eb": BigEByte,
+ "zib": BigZiByte,
+ "zb": BigZByte,
+ "yib": BigYiByte,
+ "yb": BigYByte,
+ // Without suffix
+ "": BigByte,
+ "ki": BigKiByte,
+ "k": BigKByte,
+ "mi": BigMiByte,
+ "m": BigMByte,
+ "gi": BigGiByte,
+ "g": BigGByte,
+ "ti": BigTiByte,
+ "t": BigTByte,
+ "pi": BigPiByte,
+ "p": BigPByte,
+ "ei": BigEiByte,
+ "e": BigEByte,
+ "z": BigZByte,
+ "zi": BigZiByte,
+ "y": BigYByte,
+ "yi": BigYiByte,
+}
+
+var ten = big.NewInt(10)
+
+func humanateBigBytes(s, base *big.Int, sizes []string) string {
+ if s.Cmp(ten) < 0 {
+ return fmt.Sprintf("%d B", s)
+ }
+ c := (&big.Int{}).Set(s)
+ val, mag := oomm(c, base, len(sizes)-1)
+ suffix := sizes[mag]
+ f := "%.0f %s"
+ if val < 10 {
+ f = "%.1f %s"
+ }
+
+ return fmt.Sprintf(f, val, suffix)
+
+}
+
+// BigBytes produces a human readable representation of an SI size.
+//
+// See also: ParseBigBytes.
+//
+// BigBytes(82854982) -> 83 MB
+func BigBytes(s *big.Int) string {
+ sizes := []string{"B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"}
+ return humanateBigBytes(s, bigSIExp, sizes)
+}
+
+// BigIBytes produces a human readable representation of an IEC size.
+//
+// See also: ParseBigBytes.
+//
+// BigIBytes(82854982) -> 79 MiB
+func BigIBytes(s *big.Int) string {
+ sizes := []string{"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"}
+ return humanateBigBytes(s, bigIECExp, sizes)
+}
+
+// ParseBigBytes parses a string representation of bytes into the number
+// of bytes it represents.
+//
+// See also: BigBytes, BigIBytes.
+//
+// ParseBigBytes("42 MB") -> 42000000, nil
+// ParseBigBytes("42 mib") -> 44040192, nil
+func ParseBigBytes(s string) (*big.Int, error) {
+ lastDigit := 0
+ hasComma := false
+ for _, r := range s {
+ if !(unicode.IsDigit(r) || r == '.' || r == ',') {
+ break
+ }
+ if r == ',' {
+ hasComma = true
+ }
+ lastDigit++
+ }
+
+ num := s[:lastDigit]
+ if hasComma {
+ num = strings.Replace(num, ",", "", -1)
+ }
+
+ val := &big.Rat{}
+ _, err := fmt.Sscanf(num, "%f", val)
+ if err != nil {
+ return nil, err
+ }
+
+ extra := strings.ToLower(strings.TrimSpace(s[lastDigit:]))
+ if m, ok := bigBytesSizeTable[extra]; ok {
+ mv := (&big.Rat{}).SetInt(m)
+ val.Mul(val, mv)
+ rv := &big.Int{}
+ rv.Div(val.Num(), val.Denom())
+ return rv, nil
+ }
+
+ return nil, fmt.Errorf("unhandled size name: %v", extra)
+}
diff --git a/vendor/github.com/dustin/go-humanize/bytes.go b/vendor/github.com/dustin/go-humanize/bytes.go
new file mode 100644
index 0000000..0b498f4
--- /dev/null
+++ b/vendor/github.com/dustin/go-humanize/bytes.go
@@ -0,0 +1,143 @@
+package humanize
+
+import (
+ "fmt"
+ "math"
+ "strconv"
+ "strings"
+ "unicode"
+)
+
+// IEC Sizes.
+// kibis of bits
+const (
+ Byte = 1 << (iota * 10)
+ KiByte
+ MiByte
+ GiByte
+ TiByte
+ PiByte
+ EiByte
+)
+
+// SI Sizes.
+const (
+ IByte = 1
+ KByte = IByte * 1000
+ MByte = KByte * 1000
+ GByte = MByte * 1000
+ TByte = GByte * 1000
+ PByte = TByte * 1000
+ EByte = PByte * 1000
+)
+
+var bytesSizeTable = map[string]uint64{
+ "b": Byte,
+ "kib": KiByte,
+ "kb": KByte,
+ "mib": MiByte,
+ "mb": MByte,
+ "gib": GiByte,
+ "gb": GByte,
+ "tib": TiByte,
+ "tb": TByte,
+ "pib": PiByte,
+ "pb": PByte,
+ "eib": EiByte,
+ "eb": EByte,
+ // Without suffix
+ "": Byte,
+ "ki": KiByte,
+ "k": KByte,
+ "mi": MiByte,
+ "m": MByte,
+ "gi": GiByte,
+ "g": GByte,
+ "ti": TiByte,
+ "t": TByte,
+ "pi": PiByte,
+ "p": PByte,
+ "ei": EiByte,
+ "e": EByte,
+}
+
+func logn(n, b float64) float64 {
+ return math.Log(n) / math.Log(b)
+}
+
+func humanateBytes(s uint64, base float64, sizes []string) string {
+ if s < 10 {
+ return fmt.Sprintf("%d B", s)
+ }
+ e := math.Floor(logn(float64(s), base))
+ suffix := sizes[int(e)]
+ val := math.Floor(float64(s)/math.Pow(base, e)*10+0.5) / 10
+ f := "%.0f %s"
+ if val < 10 {
+ f = "%.1f %s"
+ }
+
+ return fmt.Sprintf(f, val, suffix)
+}
+
+// Bytes produces a human readable representation of an SI size.
+//
+// See also: ParseBytes.
+//
+// Bytes(82854982) -> 83 MB
+func Bytes(s uint64) string {
+ sizes := []string{"B", "kB", "MB", "GB", "TB", "PB", "EB"}
+ return humanateBytes(s, 1000, sizes)
+}
+
+// IBytes produces a human readable representation of an IEC size.
+//
+// See also: ParseBytes.
+//
+// IBytes(82854982) -> 79 MiB
+func IBytes(s uint64) string {
+ sizes := []string{"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB"}
+ return humanateBytes(s, 1024, sizes)
+}
+
+// ParseBytes parses a string representation of bytes into the number
+// of bytes it represents.
+//
+// See Also: Bytes, IBytes.
+//
+// ParseBytes("42 MB") -> 42000000, nil
+// ParseBytes("42 mib") -> 44040192, nil
+func ParseBytes(s string) (uint64, error) {
+ lastDigit := 0
+ hasComma := false
+ for _, r := range s {
+ if !(unicode.IsDigit(r) || r == '.' || r == ',') {
+ break
+ }
+ if r == ',' {
+ hasComma = true
+ }
+ lastDigit++
+ }
+
+ num := s[:lastDigit]
+ if hasComma {
+ num = strings.Replace(num, ",", "", -1)
+ }
+
+ f, err := strconv.ParseFloat(num, 64)
+ if err != nil {
+ return 0, err
+ }
+
+ extra := strings.ToLower(strings.TrimSpace(s[lastDigit:]))
+ if m, ok := bytesSizeTable[extra]; ok {
+ f *= float64(m)
+ if f >= math.MaxUint64 {
+ return 0, fmt.Errorf("too large: %v", s)
+ }
+ return uint64(f), nil
+ }
+
+ return 0, fmt.Errorf("unhandled size name: %v", extra)
+}
diff --git a/vendor/github.com/dustin/go-humanize/comma.go b/vendor/github.com/dustin/go-humanize/comma.go
new file mode 100644
index 0000000..520ae3e
--- /dev/null
+++ b/vendor/github.com/dustin/go-humanize/comma.go
@@ -0,0 +1,116 @@
+package humanize
+
+import (
+ "bytes"
+ "math"
+ "math/big"
+ "strconv"
+ "strings"
+)
+
+// Comma produces a string form of the given number in base 10 with
+// commas after every three orders of magnitude.
+//
+// e.g. Comma(834142) -> 834,142
+func Comma(v int64) string {
+ sign := ""
+
+ // Min int64 can't be negated to a usable value, so it has to be special cased.
+ if v == math.MinInt64 {
+ return "-9,223,372,036,854,775,808"
+ }
+
+ if v < 0 {
+ sign = "-"
+ v = 0 - v
+ }
+
+ parts := []string{"", "", "", "", "", "", ""}
+ j := len(parts) - 1
+
+ for v > 999 {
+ parts[j] = strconv.FormatInt(v%1000, 10)
+ switch len(parts[j]) {
+ case 2:
+ parts[j] = "0" + parts[j]
+ case 1:
+ parts[j] = "00" + parts[j]
+ }
+ v = v / 1000
+ j--
+ }
+ parts[j] = strconv.Itoa(int(v))
+ return sign + strings.Join(parts[j:], ",")
+}
+
+// Commaf produces a string form of the given number in base 10 with
+// commas after every three orders of magnitude.
+//
+// e.g. Commaf(834142.32) -> 834,142.32
+func Commaf(v float64) string {
+ buf := &bytes.Buffer{}
+ if v < 0 {
+ buf.Write([]byte{'-'})
+ v = 0 - v
+ }
+
+ comma := []byte{','}
+
+ parts := strings.Split(strconv.FormatFloat(v, 'f', -1, 64), ".")
+ pos := 0
+ if len(parts[0])%3 != 0 {
+ pos += len(parts[0]) % 3
+ buf.WriteString(parts[0][:pos])
+ buf.Write(comma)
+ }
+ for ; pos < len(parts[0]); pos += 3 {
+ buf.WriteString(parts[0][pos : pos+3])
+ buf.Write(comma)
+ }
+ buf.Truncate(buf.Len() - 1)
+
+ if len(parts) > 1 {
+ buf.Write([]byte{'.'})
+ buf.WriteString(parts[1])
+ }
+ return buf.String()
+}
+
+// CommafWithDigits works like the Commaf but limits the resulting
+// string to the given number of decimal places.
+//
+// e.g. CommafWithDigits(834142.32, 1) -> 834,142.3
+func CommafWithDigits(f float64, decimals int) string {
+ return stripTrailingDigits(Commaf(f), decimals)
+}
+
+// BigComma produces a string form of the given big.Int in base 10
+// with commas after every three orders of magnitude.
+func BigComma(b *big.Int) string {
+ sign := ""
+ if b.Sign() < 0 {
+ sign = "-"
+ b.Abs(b)
+ }
+
+ athousand := big.NewInt(1000)
+ c := (&big.Int{}).Set(b)
+ _, m := oom(c, athousand)
+ parts := make([]string, m+1)
+ j := len(parts) - 1
+
+ mod := &big.Int{}
+ for b.Cmp(athousand) >= 0 {
+ b.DivMod(b, athousand, mod)
+ parts[j] = strconv.FormatInt(mod.Int64(), 10)
+ switch len(parts[j]) {
+ case 2:
+ parts[j] = "0" + parts[j]
+ case 1:
+ parts[j] = "00" + parts[j]
+ }
+ j--
+ }
+ parts[j] = strconv.Itoa(int(b.Int64()))
+ return sign + strings.Join(parts[j:], ",")
+}
diff --git a/vendor/github.com/dustin/go-humanize/commaf.go b/vendor/github.com/dustin/go-humanize/commaf.go
new file mode 100644
index 0000000..620690d
--- /dev/null
+++ b/vendor/github.com/dustin/go-humanize/commaf.go
@@ -0,0 +1,40 @@
+// +build go1.6
+
+package humanize
+
+import (
+ "bytes"
+ "math/big"
+ "strings"
+)
+
+// BigCommaf produces a string form of the given big.Float in base 10
+// with commas after every three orders of magnitude.
+func BigCommaf(v *big.Float) string {
+ buf := &bytes.Buffer{}
+ if v.Sign() < 0 {
+ buf.Write([]byte{'-'})
+ v.Abs(v)
+ }
+
+ comma := []byte{','}
+
+ parts := strings.Split(v.Text('f', -1), ".")
+ pos := 0
+ if len(parts[0])%3 != 0 {
+ pos += len(parts[0]) % 3
+ buf.WriteString(parts[0][:pos])
+ buf.Write(comma)
+ }
+ for ; pos < len(parts[0]); pos += 3 {
+ buf.WriteString(parts[0][pos : pos+3])
+ buf.Write(comma)
+ }
+ buf.Truncate(buf.Len() - 1)
+
+ if len(parts) > 1 {
+ buf.Write([]byte{'.'})
+ buf.WriteString(parts[1])
+ }
+ return buf.String()
+}
diff --git a/vendor/github.com/dustin/go-humanize/ftoa.go b/vendor/github.com/dustin/go-humanize/ftoa.go
new file mode 100644
index 0000000..1c62b64
--- /dev/null
+++ b/vendor/github.com/dustin/go-humanize/ftoa.go
@@ -0,0 +1,46 @@
+package humanize
+
+import (
+ "strconv"
+ "strings"
+)
+
+func stripTrailingZeros(s string) string {
+ offset := len(s) - 1
+ for offset > 0 {
+ if s[offset] == '.' {
+ offset--
+ break
+ }
+ if s[offset] != '0' {
+ break
+ }
+ offset--
+ }
+ return s[:offset+1]
+}
+
+func stripTrailingDigits(s string, digits int) string {
+ if i := strings.Index(s, "."); i >= 0 {
+ if digits <= 0 {
+ return s[:i]
+ }
+ i++
+ if i+digits >= len(s) {
+ return s
+ }
+ return s[:i+digits]
+ }
+ return s
+}
+
+// Ftoa converts a float to a string with no trailing zeros.
+func Ftoa(num float64) string {
+ return stripTrailingZeros(strconv.FormatFloat(num, 'f', 6, 64))
+}
+
+// FtoaWithDigits converts a float to a string but limits the resulting string
+// to the given number of decimal places, and no trailing zeros.
+func FtoaWithDigits(num float64, digits int) string {
+ return stripTrailingZeros(stripTrailingDigits(strconv.FormatFloat(num, 'f', 6, 64), digits))
+}
diff --git a/vendor/github.com/dustin/go-humanize/humanize.go b/vendor/github.com/dustin/go-humanize/humanize.go
new file mode 100644
index 0000000..a2c2da3
--- /dev/null
+++ b/vendor/github.com/dustin/go-humanize/humanize.go
@@ -0,0 +1,8 @@
+/*
+Package humanize converts boring ugly numbers to human-friendly strings and back.
+
+Durations can be turned into strings such as "3 days ago", numbers
+representing sizes like 82854982 into useful strings like, "83 MB" or
+"79 MiB" (whichever you prefer).
+*/
+package humanize
diff --git a/vendor/github.com/dustin/go-humanize/number.go b/vendor/github.com/dustin/go-humanize/number.go
new file mode 100644
index 0000000..dec6186
--- /dev/null
+++ b/vendor/github.com/dustin/go-humanize/number.go
@@ -0,0 +1,192 @@
+package humanize
+
+/*
+Slightly adapted from the source to fit go-humanize.
+
+Author: https://github.com/gorhill
+Source: https://gist.github.com/gorhill/5285193
+
+*/
+
+import (
+ "math"
+ "strconv"
+)
+
+var (
+ renderFloatPrecisionMultipliers = [...]float64{
+ 1,
+ 10,
+ 100,
+ 1000,
+ 10000,
+ 100000,
+ 1000000,
+ 10000000,
+ 100000000,
+ 1000000000,
+ }
+
+ renderFloatPrecisionRounders = [...]float64{
+ 0.5,
+ 0.05,
+ 0.005,
+ 0.0005,
+ 0.00005,
+ 0.000005,
+ 0.0000005,
+ 0.00000005,
+ 0.000000005,
+ 0.0000000005,
+ }
+)
+
+// FormatFloat produces a formatted number as string based on the following user-specified criteria:
+// * thousands separator
+// * decimal separator
+// * decimal precision
+//
+// Usage: s := RenderFloat(format, n)
+// The format parameter tells how to render the number n.
+//
+// See examples: http://play.golang.org/p/LXc1Ddm1lJ
+//
+// Examples of format strings, given n = 12345.6789:
+// "#,###.##" => "12,345.67"
+// "#,###." => "12,345"
+// "#,###" => "12345,678"
+// "#\u202F###,##" => "12 345,68"
+// "#.###,###### => 12.345,678900
+// "" (aka default format) => 12,345.67
+//
+// The highest precision allowed is 9 digits after the decimal symbol.
+// There is also a version for integer number, FormatInteger(),
+// which is convenient for calls within template.
+func FormatFloat(format string, n float64) string {
+ // Special cases:
+ // NaN = "NaN"
+ // +Inf = "+Infinity"
+ // -Inf = "-Infinity"
+ if math.IsNaN(n) {
+ return "NaN"
+ }
+ if n > math.MaxFloat64 {
+ return "Infinity"
+ }
+ if n < -math.MaxFloat64 {
+ return "-Infinity"
+ }
+
+ // default format
+ precision := 2
+ decimalStr := "."
+ thousandStr := ","
+ positiveStr := ""
+ negativeStr := "-"
+
+ if len(format) > 0 {
+ format := []rune(format)
+
+ // If there is an explicit format directive,
+ // then default values are these:
+ precision = 9
+ thousandStr = ""
+
+ // collect indices of meaningful formatting directives
+ formatIndx := []int{}
+ for i, char := range format {
+ if char != '#' && char != '0' {
+ formatIndx = append(formatIndx, i)
+ }
+ }
+
+ if len(formatIndx) > 0 {
+ // Directive at index 0:
+ // Must be a '+'
+ // Raise an error if not the case
+ // index: 0123456789
+ // +0.000,000
+ // +000,000.0
+ // +0000.00
+ // +0000
+ if formatIndx[0] == 0 {
+ if format[formatIndx[0]] != '+' {
+ panic("RenderFloat(): invalid positive sign directive")
+ }
+ positiveStr = "+"
+ formatIndx = formatIndx[1:]
+ }
+
+ // Two directives:
+ // First is thousands separator
+ // Raise an error if not followed by 3-digit
+ // 0123456789
+ // 0.000,000
+ // 000,000.00
+ if len(formatIndx) == 2 {
+ if (formatIndx[1] - formatIndx[0]) != 4 {
+ panic("RenderFloat(): thousands separator directive must be followed by 3 digit-specifiers")
+ }
+ thousandStr = string(format[formatIndx[0]])
+ formatIndx = formatIndx[1:]
+ }
+
+ // One directive:
+ // Directive is decimal separator
+ // The number of digit-specifier following the separator indicates wanted precision
+ // 0123456789
+ // 0.00
+ // 000,0000
+ if len(formatIndx) == 1 {
+ decimalStr = string(format[formatIndx[0]])
+ precision = len(format) - formatIndx[0] - 1
+ }
+ }
+ }
+
+ // generate sign part
+ var signStr string
+ if n >= 0.000000001 {
+ signStr = positiveStr
+ } else if n <= -0.000000001 {
+ signStr = negativeStr
+ n = -n
+ } else {
+ signStr = ""
+ n = 0.0
+ }
+
+ // split number into integer and fractional parts
+ intf, fracf := math.Modf(n + renderFloatPrecisionRounders[precision])
+
+ // generate integer part string
+ intStr := strconv.FormatInt(int64(intf), 10)
+
+ // add thousand separator if required
+ if len(thousandStr) > 0 {
+ for i := len(intStr); i > 3; {
+ i -= 3
+ intStr = intStr[:i] + thousandStr + intStr[i:]
+ }
+ }
+
+ // no fractional part, we can leave now
+ if precision == 0 {
+ return signStr + intStr
+ }
+
+ // generate fractional part
+ fracStr := strconv.Itoa(int(fracf * renderFloatPrecisionMultipliers[precision]))
+ // may need padding
+ if len(fracStr) < precision {
+ fracStr = "000000000000000"[:precision-len(fracStr)] + fracStr
+ }
+
+ return signStr + intStr + decimalStr + fracStr
+}
+
+// FormatInteger produces a formatted number as string.
+// See FormatFloat.
+func FormatInteger(format string, n int) string {
+ return FormatFloat(format, float64(n))
+}
diff --git a/vendor/github.com/dustin/go-humanize/ordinals.go b/vendor/github.com/dustin/go-humanize/ordinals.go
new file mode 100644
index 0000000..43d88a8
--- /dev/null
+++ b/vendor/github.com/dustin/go-humanize/ordinals.go
@@ -0,0 +1,25 @@
+package humanize
+
+import "strconv"
+
+// Ordinal gives you the input number in a rank/ordinal format.
+//
+// Ordinal(3) -> 3rd
+func Ordinal(x int) string {
+ suffix := "th"
+ switch x % 10 {
+ case 1:
+ if x%100 != 11 {
+ suffix = "st"
+ }
+ case 2:
+ if x%100 != 12 {
+ suffix = "nd"
+ }
+ case 3:
+ if x%100 != 13 {
+ suffix = "rd"
+ }
+ }
+ return strconv.Itoa(x) + suffix
+}
diff --git a/vendor/github.com/dustin/go-humanize/si.go b/vendor/github.com/dustin/go-humanize/si.go
new file mode 100644
index 0000000..ae659e0
--- /dev/null
+++ b/vendor/github.com/dustin/go-humanize/si.go
@@ -0,0 +1,123 @@
+package humanize
+
+import (
+ "errors"
+ "math"
+ "regexp"
+ "strconv"
+)
+
+var siPrefixTable = map[float64]string{
+ -24: "y", // yocto
+ -21: "z", // zepto
+ -18: "a", // atto
+ -15: "f", // femto
+ -12: "p", // pico
+ -9: "n", // nano
+ -6: "µ", // micro
+ -3: "m", // milli
+ 0: "",
+ 3: "k", // kilo
+ 6: "M", // mega
+ 9: "G", // giga
+ 12: "T", // tera
+ 15: "P", // peta
+ 18: "E", // exa
+ 21: "Z", // zetta
+ 24: "Y", // yotta
+}
+
+var revSIPrefixTable = revfmap(siPrefixTable)
+
+// revfmap reverses the map and precomputes the power multiplier
+func revfmap(in map[float64]string) map[string]float64 {
+ rv := map[string]float64{}
+ for k, v := range in {
+ rv[v] = math.Pow(10, k)
+ }
+ return rv
+}
+
+var riParseRegex *regexp.Regexp
+
+func init() {
+ ri := `^([\-0-9.]+)\s?([`
+ for _, v := range siPrefixTable {
+ ri += v
+ }
+ ri += `]?)(.*)`
+
+ riParseRegex = regexp.MustCompile(ri)
+}
+
+// ComputeSI finds the most appropriate SI prefix for the given number
+// and returns the prefix along with the value adjusted to be within
+// that prefix.
+//
+// See also: SI, ParseSI.
+//
+// e.g. ComputeSI(2.2345e-12) -> (2.2345, "p")
+func ComputeSI(input float64) (float64, string) {
+ if input == 0 {
+ return 0, ""
+ }
+ mag := math.Abs(input)
+ exponent := math.Floor(logn(mag, 10))
+ exponent = math.Floor(exponent/3) * 3
+
+ value := mag / math.Pow(10, exponent)
+
+ // Handle special case where value is exactly 1000.0
+ // Should return 1 M instead of 1000 k
+ if value == 1000.0 {
+ exponent += 3
+ value = mag / math.Pow(10, exponent)
+ }
+
+ value = math.Copysign(value, input)
+
+ prefix := siPrefixTable[exponent]
+ return value, prefix
+}
+
+// SI returns a string with default formatting.
+//
+// SI uses Ftoa to format float value, removing trailing zeros.
+//
+// See also: ComputeSI, ParseSI.
+//
+// e.g. SI(1000000, "B") -> 1 MB
+// e.g. SI(2.2345e-12, "F") -> 2.2345 pF
+func SI(input float64, unit string) string {
+ value, prefix := ComputeSI(input)
+ return Ftoa(value) + " " + prefix + unit
+}
+
+// SIWithDigits works like SI but limits the resulting string to the
+// given number of decimal places.
+//
+// e.g. SIWithDigits(1000000, 0, "B") -> 1 MB
+// e.g. SIWithDigits(2.2345e-12, 2, "F") -> 2.23 pF
+func SIWithDigits(input float64, decimals int, unit string) string {
+ value, prefix := ComputeSI(input)
+ return FtoaWithDigits(value, decimals) + " " + prefix + unit
+}
+
+var errInvalid = errors.New("invalid input")
+
+// ParseSI parses an SI string back into the number and unit.
+//
+// See also: SI, ComputeSI.
+//
+// e.g. ParseSI("2.2345 pF") -> (2.2345e-12, "F", nil)
+func ParseSI(input string) (float64, string, error) {
+ found := riParseRegex.FindStringSubmatch(input)
+ if len(found) != 4 {
+ return 0, "", errInvalid
+ }
+ mag := revSIPrefixTable[found[2]]
+ unit := found[3]
+
+ base, err := strconv.ParseFloat(found[1], 64)
+ return base * mag, unit, err
+}
diff --git a/vendor/github.com/dustin/go-humanize/times.go b/vendor/github.com/dustin/go-humanize/times.go
new file mode 100644
index 0000000..dd3fbf5
--- /dev/null
+++ b/vendor/github.com/dustin/go-humanize/times.go
@@ -0,0 +1,117 @@
+package humanize
+
+import (
+ "fmt"
+ "math"
+ "sort"
+ "time"
+)
+
+// Seconds-based time units
+const (
+ Day = 24 * time.Hour
+ Week = 7 * Day
+ Month = 30 * Day
+ Year = 12 * Month
+ LongTime = 37 * Year
+)
+
+// Time formats a time into a relative string.
+//
+// Time(someT) -> "3 weeks ago"
+func Time(then time.Time) string {
+ return RelTime(then, time.Now(), "ago", "from now")
+}
+
+// A RelTimeMagnitude struct contains a relative time point at which
+// the relative format of time will switch to a new format string. A
+// slice of these in ascending order by their "D" field is passed to
+// CustomRelTime to format durations.
+//
+// The Format field is a string that may contain a "%s" which will be
+// replaced with the appropriate signed label (e.g. "ago" or "from
+// now") and a "%d" that will be replaced by the quantity.
+//
+// The DivBy field is the amount of time the time difference must be
+// divided by in order to display correctly.
+//
+// e.g. if D is 2*time.Minute and you want to display "%d minutes %s"
+// DivBy should be time.Minute so whatever the duration is will be
+// expressed in minutes.
+type RelTimeMagnitude struct {
+ D time.Duration
+ Format string
+ DivBy time.Duration
+}
+
+var defaultMagnitudes = []RelTimeMagnitude{
+ {time.Second, "now", time.Second},
+ {2 * time.Second, "1 second %s", 1},
+ {time.Minute, "%d seconds %s", time.Second},
+ {2 * time.Minute, "1 minute %s", 1},
+ {time.Hour, "%d minutes %s", time.Minute},
+ {2 * time.Hour, "1 hour %s", 1},
+ {Day, "%d hours %s", time.Hour},
+ {2 * Day, "1 day %s", 1},
+ {Week, "%d days %s", Day},
+ {2 * Week, "1 week %s", 1},
+ {Month, "%d weeks %s", Week},
+ {2 * Month, "1 month %s", 1},
+ {Year, "%d months %s", Month},
+ {18 * Month, "1 year %s", 1},
+ {2 * Year, "2 years %s", 1},
+ {LongTime, "%d years %s", Year},
+ {math.MaxInt64, "a long while %s", 1},
+}
+
+// RelTime formats a time into a relative string.
+//
+// It takes two times and two labels. In addition to the generic time
+// delta string (e.g. 5 minutes), the labels are used applied so that
+// the label corresponding to the smaller time is applied.
+//
+// RelTime(timeInPast, timeInFuture, "earlier", "later") -> "3 weeks earlier"
+func RelTime(a, b time.Time, albl, blbl string) string {
+ return CustomRelTime(a, b, albl, blbl, defaultMagnitudes)
+}
+
+// CustomRelTime formats a time into a relative string.
+//
+// It takes two times two labels and a table of relative time formats.
+// In addition to the generic time delta string (e.g. 5 minutes), the
+// labels are used applied so that the label corresponding to the
+// smaller time is applied.
+func CustomRelTime(a, b time.Time, albl, blbl string, magnitudes []RelTimeMagnitude) string {
+ lbl := albl
+ diff := b.Sub(a)
+
+ if a.After(b) {
+ lbl = blbl
+ diff = a.Sub(b)
+ }
+
+ n := sort.Search(len(magnitudes), func(i int) bool {
+ return magnitudes[i].D > diff
+ })
+
+ if n >= len(magnitudes) {
+ n = len(magnitudes) - 1
+ }
+ mag := magnitudes[n]
+ args := []interface{}{}
+ escaped := false
+ for _, ch := range mag.Format {
+ if escaped {
+ switch ch {
+ case 's':
+ args = append(args, lbl)
+ case 'd':
+ args = append(args, diff/mag.DivBy)
+ }
+ escaped = false
+ } else {
+ escaped = ch == '%'
+ }
+ }
+ return fmt.Sprintf(mag.Format, args...)
+}
diff --git a/vendor/github.com/go-chi/chi/.gitignore b/vendor/github.com/go-chi/chi/.gitignore
new file mode 100644
index 0000000..ba22c99
--- /dev/null
+++ b/vendor/github.com/go-chi/chi/.gitignore
@@ -0,0 +1,3 @@
+.idea
+*.sw?
+.vscode
diff --git a/vendor/github.com/go-chi/chi/.travis.yml b/vendor/github.com/go-chi/chi/.travis.yml
new file mode 100644
index 0000000..de3287e
--- /dev/null
+++ b/vendor/github.com/go-chi/chi/.travis.yml
@@ -0,0 +1,18 @@
+language: go
+
+go:
+ - 1.10.x
+ - 1.11.x
+ - 1.12.x
+
+script:
+ - go get -d -t ./...
+ - go vet ./...
+ - go test ./...
+ - >
+ go_version=$(go version);
+ if [ ${go_version:13:4} = "1.12" ]; then
+ go get -u golang.org/x/tools/cmd/goimports;
+ goimports -d -e ./ | grep '.*' && { echo; echo "Aborting due to non-empty goimports output."; exit 1; } || :;
+ fi
+
diff --git a/vendor/github.com/go-chi/chi/CHANGELOG.md b/vendor/github.com/go-chi/chi/CHANGELOG.md
new file mode 100644
index 0000000..d03e40c
--- /dev/null
+++ b/vendor/github.com/go-chi/chi/CHANGELOG.md
@@ -0,0 +1,139 @@
+# Changelog
+
+## v4.0.0 (2019-01-10)
+
+- chi v4 requires Go 1.10.3+ (or Go 1.9.7+) - we have deprecated support for Go 1.7 and 1.8
+- router: respond with 404 on router with no routes (#362)
+- router: additional check to ensure wildcard is at the end of a url pattern (#333)
+- middleware: deprecate use of http.CloseNotifier (#347)
+- middleware: fix RedirectSlashes to include query params on redirect (#334)
+- History of changes: see https://github.com/go-chi/chi/compare/v3.3.4...v4.0.0
+
+
+## v3.3.4 (2019-01-07)
+
+- Minor middleware improvements. No changes to core library/router. Moving v3 into its
+- own branch as a version of chi for Go 1.7, 1.8, 1.9, 1.10, 1.11
+- History of changes: see https://github.com/go-chi/chi/compare/v3.3.3...v3.3.4
+
+
+## v3.3.3 (2018-08-27)
+
+- Minor release
+- See https://github.com/go-chi/chi/compare/v3.3.2...v3.3.3
+
+
+## v3.3.2 (2017-12-22)
+
+- Support to route trailing slashes on mounted sub-routers (#281)
+- middleware: new `ContentCharset` to check matching charsets. Thank you
+ @csucu for your community contribution!
+
+
+## v3.3.1 (2017-11-20)
+
+- middleware: new `AllowContentType` handler for explicit whitelist of accepted request Content-Types
+- middleware: new `SetHeader` handler for short-hand middleware to set a response header key/value
+- Minor bug fixes
+
+
+## v3.3.0 (2017-10-10)
+
+- New chi.RegisterMethod(method) to add support for custom HTTP methods, see _examples/custom-method for usage
+- Deprecated LINK and UNLINK methods from the default list, please use `chi.RegisterMethod("LINK")` and `chi.RegisterMethod("UNLINK")` in an `init()` function
+
+
+## v3.2.1 (2017-08-31)
+
+- Add new `Match(rctx *Context, method, path string) bool` method to `Routes` interface
+ and `Mux`. Match searches the mux's routing tree for a handler that matches the method/path
+- Add new `RouteMethod` to `*Context`
+- Add new `Routes` pointer to `*Context`
+- Add new `middleware.GetHead` to route missing HEAD requests to GET handler
+- Updated benchmarks (see README)
+
+
+## v3.1.5 (2017-08-02)
+
+- Setup golint and go vet for the project
+- As per golint, we've redefined `func ServerBaseContext(h http.Handler, baseCtx context.Context) http.Handler`
+ to `func ServerBaseContext(baseCtx context.Context, h http.Handler) http.Handler`
+
+
+## v3.1.0 (2017-07-10)
+
+- Fix a few minor issues after v3 release
+- Move `docgen` sub-pkg to https://github.com/go-chi/docgen
+- Move `render` sub-pkg to https://github.com/go-chi/render
+- Add new `URLFormat` handler to chi/middleware sub-pkg to make working with url mime
+ suffixes easier, ie. parsing `/articles/1.json` and `/articles/1.xml`. See comments in
+ https://github.com/go-chi/chi/blob/master/middleware/url_format.go for example usage.
+
+
+## v3.0.0 (2017-06-21)
+
+- Major update to chi library with many exciting updates, but also some *breaking changes*
+- URL parameter syntax changed from `/:id` to `/{id}` for even more flexible routing, such as
+ `/articles/{month}-{day}-{year}-{slug}`, `/articles/{id}`, and `/articles/{id}.{ext}` on the
+ same router
+- Support for regexp for routing patterns, in the form of `/{paramKey:regExp}` for example:
+ `r.Get("/articles/{name:[a-z]+}", h)` and `chi.URLParam(r, "name")`
+- Add `Method` and `MethodFunc` to `chi.Router` to allow routing definitions such as
+ `r.Method("GET", "/", h)` which provides a cleaner interface for custom handlers like
+ in `_examples/custom-handler`
+- Deprecating `mux#FileServer` helper function. Instead, we encourage users to create their
+ own using file handler with the stdlib, see `_examples/fileserver` for an example
+- Add support for LINK/UNLINK http methods via `r.Method()` and `r.MethodFunc()`
+- Moved the chi project to its own organization, to allow chi-related community packages to
+ be easily discovered and supported, at: https://github.com/go-chi
+- *NOTE:* please update your import paths to `"github.com/go-chi/chi"`
+- *NOTE:* chi v2 is still available at https://github.com/go-chi/chi/tree/v2
+
+
+## v2.1.0 (2017-03-30)
+
+- Minor improvements and update to the chi core library
+- Introduced a brand new `chi/render` sub-package to complete the story of building
+ APIs to offer a pattern for managing well-defined request / response payloads. Please
+ check out the updated `_examples/rest` example for how it works.
+- Added `MethodNotAllowed(h http.HandlerFunc)` to chi.Router interface
+
+
+## v2.0.0 (2017-01-06)
+
+- After many months of v2 being in an RC state with many companies and users running it in
+ production, the inclusion of some improvements to the middlewares, we are very pleased to
+ announce v2.0.0 of chi.
+
+
+## v2.0.0-rc1 (2016-07-26)
+
+- Huge update! chi v2 is a large refactor targetting Go 1.7+. As of Go 1.7, the popular
+ community `"net/context"` package has been included in the standard library as `"context"` and
+ utilized by `"net/http"` and `http.Request` to managing deadlines, cancelation signals and other
+ request-scoped values. We're very excited about the new context addition and are proud to
+ introduce chi v2, a minimal and powerful routing package for building large HTTP services,
+ with zero external dependencies. Chi focuses on idiomatic design and encourages the use of
+ stdlib HTTP handlers and middlwares.
+- chi v2 deprecates its `chi.Handler` interface and requires `http.Handler` or `http.HandlerFunc`
+- chi v2 stores URL routing parameters and patterns in the standard request context: `r.Context()`
+- chi v2 lower-level routing context is accessible by `chi.RouteContext(r.Context()) *chi.Context`,
+ which provides direct access to URL routing parameters, the routing path and the matching
+ routing patterns.
+- Users upgrading from chi v1 to v2, need to:
+ 1. Update the old chi.Handler signature, `func(ctx context.Context, w http.ResponseWriter, r *http.Request)` to
+ the standard http.Handler: `func(w http.ResponseWriter, r *http.Request)`
+ 2. Use `chi.URLParam(r *http.Request, paramKey string) string`
+ or `URLParamFromCtx(ctx context.Context, paramKey string) string` to access a url parameter value
+
+
+## v1.0.0 (2016-07-01)
+
+- Released chi v1 stable https://github.com/go-chi/chi/tree/v1.0.0 for Go 1.6 and older.
+
+
+## v0.9.0 (2016-03-31)
+
+- Reuse context objects via sync.Pool for zero-allocation routing [#33](https://github.com/go-chi/chi/pull/33)
+- BREAKING NOTE: due to subtle API changes, previously `chi.URLParams(ctx)["id"]` used to access url parameters
+ has changed to: `chi.URLParam(ctx, "id")`
diff --git a/vendor/github.com/go-chi/chi/CONTRIBUTING.md b/vendor/github.com/go-chi/chi/CONTRIBUTING.md
new file mode 100644
index 0000000..c0ac2df
--- /dev/null
+++ b/vendor/github.com/go-chi/chi/CONTRIBUTING.md
@@ -0,0 +1,31 @@
+# Contributing
+
+## Prerequisites
+
+1. [Install Go][go-install].
+2. Download the sources and switch the working directory:
+
+ ```bash
+ go get -u -d github.com/go-chi/chi
+ cd $GOPATH/src/github.com/go-chi/chi
+ ```
+
+## Submitting a Pull Request
+
+A typical workflow is:
+
+1. [Fork the repository.][fork] [This tip maybe also helpful.][go-fork-tip]
+2. [Create a topic branch.][branch]
+3. Add tests for your change.
+4. Run `go test`. If your tests pass, return to the step 3.
+5. Implement the change and ensure the steps from the previous step pass.
+6. Run `goimports -w .`, to ensure the new code conforms to Go formatting guideline.
+7. [Add, commit and push your changes.][git-help]
+8. [Submit a pull request.][pull-req]
+
+[go-install]: https://golang.org/doc/install
+[go-fork-tip]: http://blog.campoy.cat/2014/03/github-and-go-forking-pull-requests-and.html
+[fork]: https://help.github.com/articles/fork-a-repo
+[branch]: http://learn.github.com/p/branching.html
+[git-help]: https://guides.github.com
+[pull-req]: https://help.github.com/articles/using-pull-requests
diff --git a/vendor/github.com/go-chi/chi/LICENSE b/vendor/github.com/go-chi/chi/LICENSE
new file mode 100644
index 0000000..d99f02f
--- /dev/null
+++ b/vendor/github.com/go-chi/chi/LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2015-present Peter Kieltyka (https://github.com/pkieltyka), Google Inc.
+
+MIT License
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/vendor/github.com/go-chi/chi/README.md b/vendor/github.com/go-chi/chi/README.md
new file mode 100644
index 0000000..d36d4db
--- /dev/null
+++ b/vendor/github.com/go-chi/chi/README.md
@@ -0,0 +1,438 @@
+#
+
+
+[![GoDoc Widget]][GoDoc] [![Travis Widget]][Travis]
+
+`chi` is a lightweight, idiomatic and composable router for building Go HTTP services. It's
+especially good at helping you write large REST API services that are kept maintainable as your
+project grows and changes. `chi` is built on the new `context` package introduced in Go 1.7 to
+handle signaling, cancelation and request-scoped values across a handler chain.
+
+The focus of the project has been to seek out an elegant and comfortable design for writing
+REST API servers, written during the development of the Pressly API service that powers our
+public API service, which in turn powers all of our client-side applications.
+
+The key considerations of chi's design are: project structure, maintainability, standard http
+handlers (stdlib-only), developer productivity, and deconstructing a large system into many small
+parts. The core router `github.com/go-chi/chi` is quite small (less than 1000 LOC), but we've also
+included some useful/optional subpackages: [middleware](/middleware), [render](https://github.com/go-chi/render) and [docgen](https://github.com/go-chi/docgen). We hope you enjoy it too!
+
+## Install
+
+`go get -u github.com/go-chi/chi`
+
+
+## Features
+
+* **Lightweight** - cloc'd in ~1000 LOC for the chi router
+* **Fast** - yes, see [benchmarks](#benchmarks)
+* **100% compatible with net/http** - use any http or middleware pkg in the ecosystem that is also compatible with `net/http`
+* **Designed for modular/composable APIs** - middlewares, inline middlewares, route groups and subrouter mounting
+* **Context control** - built on new `context` package, providing value chaining, cancelations and timeouts
+* **Robust** - in production at Pressly, CloudFlare, Heroku, 99Designs, and many others (see [discussion](https://github.com/go-chi/chi/issues/91))
+* **Doc generation** - `docgen` auto-generates routing documentation from your source to JSON or Markdown
+* **No external dependencies** - plain ol' Go stdlib + net/http
+
+
+## Examples
+
+See [_examples/](https://github.com/go-chi/chi/blob/master/_examples/) for a variety of examples.
+
+
+**As easy as:**
+
+```go
+package main
+
+import (
+ "net/http"
+ "github.com/go-chi/chi"
+)
+
+func main() {
+ r := chi.NewRouter()
+ r.Get("/", func(w http.ResponseWriter, r *http.Request) {
+ w.Write([]byte("welcome"))
+ })
+ http.ListenAndServe(":3000", r)
+}
+```
+
+**REST Preview:**
+
+Here is a little preview of how routing looks like with chi. Also take a look at the generated routing docs
+in JSON ([routes.json](https://github.com/go-chi/chi/blob/master/_examples/rest/routes.json)) and in
+Markdown ([routes.md](https://github.com/go-chi/chi/blob/master/_examples/rest/routes.md)).
+
+I highly recommend reading the source of the [examples](https://github.com/go-chi/chi/blob/master/_examples/) listed
+above, they will show you all the features of chi and serve as a good form of documentation.
+
+```go
+import (
+ //...
+ "context"
+ "github.com/go-chi/chi"
+ "github.com/go-chi/chi/middleware"
+)
+
+func main() {
+ r := chi.NewRouter()
+
+ // A good base middleware stack
+ r.Use(middleware.RequestID)
+ r.Use(middleware.RealIP)
+ r.Use(middleware.Logger)
+ r.Use(middleware.Recoverer)
+
+ // Set a timeout value on the request context (ctx), that will signal
+ // through ctx.Done() that the request has timed out and further
+ // processing should be stopped.
+ r.Use(middleware.Timeout(60 * time.Second))
+
+ r.Get("/", func(w http.ResponseWriter, r *http.Request) {
+ w.Write([]byte("hi"))
+ })
+
+ // RESTy routes for "articles" resource
+ r.Route("/articles", func(r chi.Router) {
+ r.With(paginate).Get("/", listArticles) // GET /articles
+ r.With(paginate).Get("/{month}-{day}-{year}", listArticlesByDate) // GET /articles/01-16-2017
+
+ r.Post("/", createArticle) // POST /articles
+ r.Get("/search", searchArticles) // GET /articles/search
+
+ // Regexp url parameters:
+ r.Get("/{articleSlug:[a-z-]+}", getArticleBySlug) // GET /articles/home-is-toronto
+
+ // Subrouters:
+ r.Route("/{articleID}", func(r chi.Router) {
+ r.Use(ArticleCtx)
+ r.Get("/", getArticle) // GET /articles/123
+ r.Put("/", updateArticle) // PUT /articles/123
+ r.Delete("/", deleteArticle) // DELETE /articles/123
+ })
+ })
+
+ // Mount the admin sub-router
+ r.Mount("/admin", adminRouter())
+
+ http.ListenAndServe(":3333", r)
+}
+
+func ArticleCtx(next http.Handler) http.Handler {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ articleID := chi.URLParam(r, "articleID")
+ article, err := dbGetArticle(articleID)
+ if err != nil {
+ http.Error(w, http.StatusText(404), 404)
+ return
+ }
+ ctx := context.WithValue(r.Context(), "article", article)
+ next.ServeHTTP(w, r.WithContext(ctx))
+ })
+}
+
+func getArticle(w http.ResponseWriter, r *http.Request) {
+ ctx := r.Context()
+ article, ok := ctx.Value("article").(*Article)
+ if !ok {
+ http.Error(w, http.StatusText(422), 422)
+ return
+ }
+ w.Write([]byte(fmt.Sprintf("title:%s", article.Title)))
+}
+
+// A completely separate router for administrator routes
+func adminRouter() http.Handler {
+ r := chi.NewRouter()
+ r.Use(AdminOnly)
+ r.Get("/", adminIndex)
+ r.Get("/accounts", adminListAccounts)
+ return r
+}
+
+func AdminOnly(next http.Handler) http.Handler {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ ctx := r.Context()
+ perm, ok := ctx.Value("acl.permission").(YourPermissionType)
+ if !ok || !perm.IsAdmin() {
+ http.Error(w, http.StatusText(403), 403)
+ return
+ }
+ next.ServeHTTP(w, r)
+ })
+}
+```
+
+
+## Router design
+
+chi's router is based on a kind of [Patricia Radix trie](https://en.wikipedia.org/wiki/Radix_tree).
+The router is fully compatible with `net/http`.
+
+Built on top of the tree is the `Router` interface:
+
+```go
+// Router consisting of the core routing methods used by chi's Mux,
+// using only the standard net/http.
+type Router interface {
+ http.Handler
+ Routes
+
+ // Use appends one of more middlewares onto the Router stack.
+ Use(middlewares ...func(http.Handler) http.Handler)
+
+ // With adds inline middlewares for an endpoint handler.
+ With(middlewares ...func(http.Handler) http.Handler) Router
+
+ // Group adds a new inline-Router along the current routing
+ // path, with a fresh middleware stack for the inline-Router.
+ Group(fn func(r Router)) Router
+
+ // Route mounts a sub-Router along a `pattern`` string.
+ Route(pattern string, fn func(r Router)) Router
+
+ // Mount attaches another http.Handler along ./pattern/*
+ Mount(pattern string, h http.Handler)
+
+ // Handle and HandleFunc adds routes for `pattern` that matches
+ // all HTTP methods.
+ Handle(pattern string, h http.Handler)
+ HandleFunc(pattern string, h http.HandlerFunc)
+
+ // Method and MethodFunc adds routes for `pattern` that matches
+ // the `method` HTTP method.
+ Method(method, pattern string, h http.Handler)
+ MethodFunc(method, pattern string, h http.HandlerFunc)
+
+ // HTTP-method routing along `pattern`
+ Connect(pattern string, h http.HandlerFunc)
+ Delete(pattern string, h http.HandlerFunc)
+ Get(pattern string, h http.HandlerFunc)
+ Head(pattern string, h http.HandlerFunc)
+ Options(pattern string, h http.HandlerFunc)
+ Patch(pattern string, h http.HandlerFunc)
+ Post(pattern string, h http.HandlerFunc)
+ Put(pattern string, h http.HandlerFunc)
+ Trace(pattern string, h http.HandlerFunc)
+
+ // NotFound defines a handler to respond whenever a route could
+ // not be found.
+ NotFound(h http.HandlerFunc)
+
+ // MethodNotAllowed defines a handler to respond whenever a method is
+ // not allowed.
+ MethodNotAllowed(h http.HandlerFunc)
+}
+
+// Routes interface adds two methods for router traversal, which is also
+// used by the github.com/go-chi/docgen package to generate documentation for Routers.
+type Routes interface {
+ // Routes returns the routing tree in an easily traversable structure.
+ Routes() []Route
+
+ // Middlewares returns the list of middlewares in use by the router.
+ Middlewares() Middlewares
+
+ // Match searches the routing tree for a handler that matches
+ // the method/path - similar to routing a http request, but without
+ // executing the handler thereafter.
+ Match(rctx *Context, method, path string) bool
+}
+```
+
+Each routing method accepts a URL `pattern` and chain of `handlers`. The URL pattern
+supports named params (ie. `/users/{userID}`) and wildcards (ie. `/admin/*`). URL parameters
+can be fetched at runtime by calling `chi.URLParam(r, "userID")` for named parameters
+and `chi.URLParam(r, "*")` for a wildcard parameter.
+
+
+### Middleware handlers
+
+chi's middlewares are just stdlib net/http middleware handlers. There is nothing special
+about them, which means the router and all the tooling is designed to be compatible and
+friendly with any middleware in the community. This offers much better extensibility and reuse
+of packages and is at the heart of chi's purpose.
+
+Here is an example of a standard net/http middleware handler using the new request context
+available in Go. This middleware sets a hypothetical user identifier on the request
+context and calls the next handler in the chain.
+
+```go
+// HTTP middleware setting a value on the request context
+func MyMiddleware(next http.Handler) http.Handler {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ ctx := context.WithValue(r.Context(), "user", "123")
+ next.ServeHTTP(w, r.WithContext(ctx))
+ })
+}
+```
+
+
+### Request handlers
+
+chi uses standard net/http request handlers. This little snippet is an example of a http.Handler
+func that reads a user identifier from the request context - hypothetically, identifying
+the user sending an authenticated request, validated+set by a previous middleware handler.
+
+```go
+// HTTP handler accessing data from the request context.
+func MyRequestHandler(w http.ResponseWriter, r *http.Request) {
+ user := r.Context().Value("user").(string)
+ w.Write([]byte(fmt.Sprintf("hi %s", user)))
+}
+```
+
+
+### URL parameters
+
+chi's router parses and stores URL parameters right onto the request context. Here is
+an example of how to access URL params in your net/http handlers. And of course, middlewares
+are able to access the same information.
+
+```go
+// HTTP handler accessing the url routing parameters.
+func MyRequestHandler(w http.ResponseWriter, r *http.Request) {
+ userID := chi.URLParam(r, "userID") // from a route like /users/{userID}
+
+ ctx := r.Context()
+ key := ctx.Value("key").(string)
+
+ w.Write([]byte(fmt.Sprintf("hi %v, %v", userID, key)))
+}
+```
+
+
+## Middlewares
+
+chi comes equipped with an optional `middleware` package, providing a suite of standard
+`net/http` middlewares. Please note, any middleware in the ecosystem that is also compatible
+with `net/http` can be used with chi's mux.
+
+### Core middlewares
+
+-----------------------------------------------------------------------------------------------------------
+| chi/middleware Handler | description |
+|:----------------------|:---------------------------------------------------------------------------------
+| AllowContentType | Explicit whitelist of accepted request Content-Types |
+| Compress | Gzip compression for clients that accept compressed responses |
+| GetHead | Automatically route undefined HEAD requests to GET handlers |
+| Heartbeat | Monitoring endpoint to check the servers pulse |
+| Logger | Logs the start and end of each request with the elapsed processing time |
+| NoCache | Sets response headers to prevent clients from caching |
+| Profiler | Easily attach net/http/pprof to your routers |
+| RealIP | Sets a http.Request's RemoteAddr to either X-Forwarded-For or X-Real-IP |
+| Recoverer | Gracefully absorb panics and prints the stack trace |
+| RequestID | Injects a request ID into the context of each request |
+| RedirectSlashes | Redirect slashes on routing paths |
+| SetHeader | Short-hand middleware to set a response header key/value |
+| StripSlashes | Strip slashes on routing paths |
+| Throttle | Puts a ceiling on the number of concurrent requests |
+| Timeout | Signals to the request context when the timeout deadline is reached |
+| URLFormat | Parse extension from url and put it on request context |
+| WithValue | Short-hand middleware to set a key/value on the request context |
+-----------------------------------------------------------------------------------------------------------
+
+### Auxiliary middlewares & packages
+
+Please see https://github.com/go-chi for additional packages.
+
+--------------------------------------------------------------------------------------------------------------------
+| package | description |
+|:---------------------------------------------------|:-------------------------------------------------------------
+| [cors](https://github.com/go-chi/cors) | Cross-origin resource sharing (CORS) |
+| [docgen](https://github.com/go-chi/docgen) | Print chi.Router routes at runtime |
+| [jwtauth](https://github.com/go-chi/jwtauth) | JWT authentication |
+| [hostrouter](https://github.com/go-chi/hostrouter) | Domain/host based request routing |
+| [httpcoala](https://github.com/go-chi/httpcoala) | HTTP request coalescer |
+| [chi-authz](https://github.com/casbin/chi-authz) | Request ACL via https://github.com/hsluoyz/casbin |
+| [phi](https://github.com/fate-lovely/phi) | Port chi to [fasthttp](https://github.com/valyala/fasthttp) |
+--------------------------------------------------------------------------------------------------------------------
+
+please [submit a PR](./CONTRIBUTING.md) if you'd like to include a link to a chi-compatible middleware
+
+
+## context?
+
+`context` is a tiny pkg that provides simple interface to signal context across call stacks
+and goroutines. It was originally written by [Sameer Ajmani](https://github.com/Sajmani)
+and is available in stdlib since go1.7.
+
+Learn more at https://blog.golang.org/context
+
+and..
+* Docs: https://golang.org/pkg/context
+* Source: https://github.com/golang/go/tree/master/src/context
+
+
+## Benchmarks
+
+The benchmark suite: https://github.com/pkieltyka/go-http-routing-benchmark
+
+Results as of Jan 9, 2019 with Go 1.11.4 on Linux X1 Carbon laptop
+
+```shell
+BenchmarkChi_Param 3000000 475 ns/op 432 B/op 3 allocs/op
+BenchmarkChi_Param5 2000000 696 ns/op 432 B/op 3 allocs/op
+BenchmarkChi_Param20 1000000 1275 ns/op 432 B/op 3 allocs/op
+BenchmarkChi_ParamWrite 3000000 505 ns/op 432 B/op 3 allocs/op
+BenchmarkChi_GithubStatic 3000000 508 ns/op 432 B/op 3 allocs/op
+BenchmarkChi_GithubParam 2000000 669 ns/op 432 B/op 3 allocs/op
+BenchmarkChi_GithubAll 10000 134627 ns/op 87699 B/op 609 allocs/op
+BenchmarkChi_GPlusStatic 3000000 402 ns/op 432 B/op 3 allocs/op
+BenchmarkChi_GPlusParam 3000000 500 ns/op 432 B/op 3 allocs/op
+BenchmarkChi_GPlus2Params 3000000 586 ns/op 432 B/op 3 allocs/op
+BenchmarkChi_GPlusAll 200000 7237 ns/op 5616 B/op 39 allocs/op
+BenchmarkChi_ParseStatic 3000000 408 ns/op 432 B/op 3 allocs/op
+BenchmarkChi_ParseParam 3000000 488 ns/op 432 B/op 3 allocs/op
+BenchmarkChi_Parse2Params 3000000 551 ns/op 432 B/op 3 allocs/op
+BenchmarkChi_ParseAll 100000 13508 ns/op 11232 B/op 78 allocs/op
+BenchmarkChi_StaticAll 20000 81933 ns/op 67826 B/op 471 allocs/op
+```
+
+Comparison with other routers: https://gist.github.com/pkieltyka/123032f12052520aaccab752bd3e78cc
+
+NOTE: the allocs in the benchmark above are from the calls to http.Request's
+`WithContext(context.Context)` method that clones the http.Request, sets the `Context()`
+on the duplicated (alloc'd) request and returns it the new request object. This is just
+how setting context on a request in Go works.
+
+
+## Credits
+
+* Carl Jackson for https://github.com/zenazn/goji
+ * Parts of chi's thinking comes from goji, and chi's middleware package
+ sources from goji.
+* Armon Dadgar for https://github.com/armon/go-radix
+* Contributions: [@VojtechVitek](https://github.com/VojtechVitek)
+
+We'll be more than happy to see [your contributions](./CONTRIBUTING.md)!
+
+
+## Beyond REST
+
+chi is just a http router that lets you decompose request handling into many smaller layers.
+Many companies including Pressly.com (of course) use chi to write REST services for their public
+APIs. But, REST is just a convention for managing state via HTTP, and there's a lot of other pieces
+required to write a complete client-server system or network of microservices.
+
+Looking ahead beyond REST, I also recommend some newer works in the field coming from
+[gRPC](https://github.com/grpc/grpc-go), [NATS](https://nats.io), [go-kit](https://github.com/go-kit/kit)
+and even [graphql](https://github.com/graphql-go/graphql). They're all pretty cool with their
+own unique approaches and benefits. Specifically, I'd look at gRPC since it makes client-server
+communication feel like a single program on a single computer, no need to hand-write a client library
+and the request/response payloads are typed contracts. NATS is pretty amazing too as a super
+fast and lightweight pub-sub transport that can speak protobufs, with nice service discovery -
+an excellent combination with gRPC.
+
+
+## License
+
+Copyright (c) 2015-present [Peter Kieltyka](https://github.com/pkieltyka)
+
+Licensed under [MIT License](./LICENSE)
+
+[GoDoc]: https://godoc.org/github.com/go-chi/chi
+[GoDoc Widget]: https://godoc.org/github.com/go-chi/chi?status.svg
+[Travis]: https://travis-ci.org/go-chi/chi
+[Travis Widget]: https://travis-ci.org/go-chi/chi.svg?branch=master
diff --git a/vendor/github.com/go-chi/chi/chain.go b/vendor/github.com/go-chi/chi/chain.go
new file mode 100644
index 0000000..88e6846
--- /dev/null
+++ b/vendor/github.com/go-chi/chi/chain.go
@@ -0,0 +1,49 @@
+package chi
+
+import "net/http"
+
+// Chain returns a Middlewares type from a slice of middleware handlers.
+func Chain(middlewares ...func(http.Handler) http.Handler) Middlewares {
+ return Middlewares(middlewares)
+}
+
+// Handler builds and returns a http.Handler from the chain of middlewares,
+// with `h http.Handler` as the final handler.
+func (mws Middlewares) Handler(h http.Handler) http.Handler {
+ return &ChainHandler{mws, h, chain(mws, h)}
+}
+
+// HandlerFunc builds and returns a http.Handler from the chain of middlewares,
+// with `h http.Handler` as the final handler.
+func (mws Middlewares) HandlerFunc(h http.HandlerFunc) http.Handler {
+ return &ChainHandler{mws, h, chain(mws, h)}
+}
+
+// ChainHandler is a http.Handler with support for handler composition and
+// execution.
+type ChainHandler struct {
+ Middlewares Middlewares
+ Endpoint http.Handler
+ chain http.Handler
+}
+
+func (c *ChainHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+ c.chain.ServeHTTP(w, r)
+}
+
+// chain builds a http.Handler composed of an inline middleware stack and endpoint
+// handler in the order they are passed.
+func chain(middlewares []func(http.Handler) http.Handler, endpoint http.Handler) http.Handler {
+ // Return ahead of time if there aren't any middlewares for the chain
+ if len(middlewares) == 0 {
+ return endpoint
+ }
+
+ // Wrap the end handler with the middleware chain
+ h := middlewares[len(middlewares)-1](endpoint)
+ for i := len(middlewares) - 2; i >= 0; i-- {
+ h = middlewares[i](h)
+ }
+
+ return h
+}
diff --git a/vendor/github.com/go-chi/chi/chi.go b/vendor/github.com/go-chi/chi/chi.go
new file mode 100644
index 0000000..9962229
--- /dev/null
+++ b/vendor/github.com/go-chi/chi/chi.go
@@ -0,0 +1,134 @@
+//
+// Package chi is a small, idiomatic and composable router for building HTTP services.
+//
+// chi requires Go 1.7 or newer.
+//
+// Example:
+// package main
+//
+// import (
+// "net/http"
+//
+// "github.com/go-chi/chi"
+// "github.com/go-chi/chi/middleware"
+// )
+//
+// func main() {
+// r := chi.NewRouter()
+// r.Use(middleware.Logger)
+// r.Use(middleware.Recoverer)
+//
+// r.Get("/", func(w http.ResponseWriter, r *http.Request) {
+// w.Write([]byte("root."))
+// })
+//
+// http.ListenAndServe(":3333", r)
+// }
+//
+// See github.com/go-chi/chi/_examples/ for more in-depth examples.
+//
+// URL patterns allow for easy matching of path components in HTTP
+// requests. The matching components can then be accessed using
+// chi.URLParam(). All patterns must begin with a slash.
+//
+// A simple named placeholder {name} matches any sequence of characters
+// up to the next / or the end of the URL. Trailing slashes on paths must
+// be handled explicitly.
+//
+// A placeholder with a name followed by a colon allows a regular
+// expression match, for example {number:\\d+}. The regular expression
+// syntax is Go's normal regexp RE2 syntax, except that regular expressions
+// including { or } are not supported, and / will never be
+// matched. An anonymous regexp pattern is allowed, using an empty string
+// before the colon in the placeholder, such as {:\\d+}
+//
+// The special placeholder of asterisk matches the rest of the requested
+// URL. Any trailing characters in the pattern are ignored. This is the only
+// placeholder which will match / characters.
+//
+// Examples:
+// "/user/{name}" matches "/user/jsmith" but not "/user/jsmith/info" or "/user/jsmith/"
+// "/user/{name}/info" matches "/user/jsmith/info"
+// "/page/*" matches "/page/intro/latest"
+// "/page/*/index" also matches "/page/intro/latest"
+// "/date/{yyyy:\\d\\d\\d\\d}/{mm:\\d\\d}/{dd:\\d\\d}" matches "/date/2017/04/01"
+//
+package chi
+
+import "net/http"
+
+// NewRouter returns a new Mux object that implements the Router interface.
+func NewRouter() *Mux {
+ return NewMux()
+}
+
+// Router consisting of the core routing methods used by chi's Mux,
+// using only the standard net/http.
+type Router interface {
+ http.Handler
+ Routes
+
+ // Use appends one of more middlewares onto the Router stack.
+ Use(middlewares ...func(http.Handler) http.Handler)
+
+ // With adds inline middlewares for an endpoint handler.
+ With(middlewares ...func(http.Handler) http.Handler) Router
+
+ // Group adds a new inline-Router along the current routing
+ // path, with a fresh middleware stack for the inline-Router.
+ Group(fn func(r Router)) Router
+
+ // Route mounts a sub-Router along a `pattern`` string.
+ Route(pattern string, fn func(r Router)) Router
+
+ // Mount attaches another http.Handler along ./pattern/*
+ Mount(pattern string, h http.Handler)
+
+ // Handle and HandleFunc adds routes for `pattern` that matches
+ // all HTTP methods.
+ Handle(pattern string, h http.Handler)
+ HandleFunc(pattern string, h http.HandlerFunc)
+
+ // Method and MethodFunc adds routes for `pattern` that matches
+ // the `method` HTTP method.
+ Method(method, pattern string, h http.Handler)
+ MethodFunc(method, pattern string, h http.HandlerFunc)
+
+ // HTTP-method routing along `pattern`
+ Connect(pattern string, h http.HandlerFunc)
+ Delete(pattern string, h http.HandlerFunc)
+ Get(pattern string, h http.HandlerFunc)
+ Head(pattern string, h http.HandlerFunc)
+ Options(pattern string, h http.HandlerFunc)
+ Patch(pattern string, h http.HandlerFunc)
+ Post(pattern string, h http.HandlerFunc)
+ Put(pattern string, h http.HandlerFunc)
+ Trace(pattern string, h http.HandlerFunc)
+
+ // NotFound defines a handler to respond whenever a route could
+ // not be found.
+ NotFound(h http.HandlerFunc)
+
+ // MethodNotAllowed defines a handler to respond whenever a method is
+ // not allowed.
+ MethodNotAllowed(h http.HandlerFunc)
+}
+
+// Routes interface adds two methods for router traversal, which is also
+// used by the `docgen` subpackage to generation documentation for Routers.
+type Routes interface {
+ // Routes returns the routing tree in an easily traversable structure.
+ Routes() []Route
+
+ // Middlewares returns the list of middlewares in use by the router.
+ Middlewares() Middlewares
+
+ // Match searches the routing tree for a handler that matches
+ // the method/path - similar to routing a http request, but without
+ // executing the handler thereafter.
+ Match(rctx *Context, method, path string) bool
+}
+
+// Middlewares type is a slice of standard middleware handlers with methods
+// to compose middleware chains and http.Handler's.
+type Middlewares []func(http.Handler) http.Handler
diff --git a/vendor/github.com/go-chi/chi/context.go b/vendor/github.com/go-chi/chi/context.go
new file mode 100644
index 0000000..229c9cb
--- /dev/null
+++ b/vendor/github.com/go-chi/chi/context.go
@@ -0,0 +1,161 @@
+package chi
+
+import (
+ "context"
+ "net"
+ "net/http"
+ "strings"
+)
+
+var (
+ // RouteCtxKey is the context.Context key to store the request context.
+ RouteCtxKey = &contextKey{"RouteContext"}
+)
+
+// Context is the default routing context set on the root node of a
+// request context to track route patterns, URL parameters and
+// an optional routing path.
+type Context struct {
+ Routes Routes
+
+ // Routing path/method override used during the route search.
+ // See Mux#routeHTTP method.
+ RoutePath string
+ RouteMethod string
+
+ // Routing pattern stack throughout the lifecycle of the request,
+ // across all connected routers. It is a record of all matching
+ // patterns across a stack of sub-routers.
+ RoutePatterns []string
+
+ // URLParams are the stack of routeParams captured during the
+ // routing lifecycle across a stack of sub-routers.
+ URLParams RouteParams
+
+ // The endpoint routing pattern that matched the request URI path
+ // or `RoutePath` of the current sub-router. This value will update
+ // during the lifecycle of a request passing through a stack of
+ // sub-routers.
+ routePattern string
+
+ // Route parameters matched for the current sub-router. It is
+ // intentionally unexported so it cant be tampered.
+ routeParams RouteParams
+
+ // methodNotAllowed hint
+ methodNotAllowed bool
+}
+
+// NewRouteContext returns a new routing Context object.
+func NewRouteContext() *Context {
+ return &Context{}
+}
+
+// Reset a routing context to its initial state.
+func (x *Context) Reset() {
+ x.Routes = nil
+ x.RoutePath = ""
+ x.RouteMethod = ""
+ x.RoutePatterns = x.RoutePatterns[:0]
+ x.URLParams.Keys = x.URLParams.Keys[:0]
+ x.URLParams.Values = x.URLParams.Values[:0]
+
+ x.routePattern = ""
+ x.routeParams.Keys = x.routeParams.Keys[:0]
+ x.routeParams.Values = x.routeParams.Values[:0]
+ x.methodNotAllowed = false
+}
+
+// URLParam returns the corresponding URL parameter value from the request
+// routing context.
+func (x *Context) URLParam(key string) string {
+ for k := len(x.URLParams.Keys) - 1; k >= 0; k-- {
+ if x.URLParams.Keys[k] == key {
+ return x.URLParams.Values[k]
+ }
+ }
+ return ""
+}
+
+// RoutePattern builds the routing pattern string for the particular
+// request, at the particular point during routing. This means, the value
+// will change throughout the execution of a request in a router. That is
+// why its advised to only use this value after calling the next handler.
+//
+// For example,
+//
+// func Instrument(next http.Handler) http.Handler {
+// return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+// next.ServeHTTP(w, r)
+// routePattern := chi.RouteContext(r.Context()).RoutePattern()
+// measure(w, r, routePattern)
+// })
+// }
+func (x *Context) RoutePattern() string {
+ routePattern := strings.Join(x.RoutePatterns, "")
+ return strings.Replace(routePattern, "/*/", "/", -1)
+}
+
+// RouteContext returns chi's routing Context object from a
+// http.Request Context.
+func RouteContext(ctx context.Context) *Context {
+ return ctx.Value(RouteCtxKey).(*Context)
+}
+
+// URLParam returns the url parameter from a http.Request object.
+func URLParam(r *http.Request, key string) string {
+ if rctx := RouteContext(r.Context()); rctx != nil {
+ return rctx.URLParam(key)
+ }
+ return ""
+}
+
+// URLParamFromCtx returns the url parameter from a http.Request Context.
+func URLParamFromCtx(ctx context.Context, key string) string {
+ if rctx := RouteContext(ctx); rctx != nil {
+ return rctx.URLParam(key)
+ }
+ return ""
+}
+
+// RouteParams is a structure to track URL routing parameters efficiently.
+type RouteParams struct {
+ Keys, Values []string
+}
+
+// Add will append a URL parameter to the end of the route param
+func (s *RouteParams) Add(key, value string) {
+ (*s).Keys = append((*s).Keys, key)
+ (*s).Values = append((*s).Values, value)
+}
+
+// ServerBaseContext wraps an http.Handler to set the request context to the
+// `baseCtx`.
+func ServerBaseContext(baseCtx context.Context, h http.Handler) http.Handler {
+ fn := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ ctx := r.Context()
+ baseCtx := baseCtx
+
+ // Copy over default net/http server context keys
+ if v, ok := ctx.Value(http.ServerContextKey).(*http.Server); ok {
+ baseCtx = context.WithValue(baseCtx, http.ServerContextKey, v)
+ }
+ if v, ok := ctx.Value(http.LocalAddrContextKey).(net.Addr); ok {
+ baseCtx = context.WithValue(baseCtx, http.LocalAddrContextKey, v)
+ }
+
+ h.ServeHTTP(w, r.WithContext(baseCtx))
+ })
+ return fn
+}
+
+// contextKey is a value for use with context.WithValue. It's used as
+// a pointer so it fits in an interface{} without allocation. This technique
+// for defining context keys was copied from Go 1.7's new use of context in net/http.
+type contextKey struct {
+ name string
+}
+
+func (k *contextKey) String() string {
+ return "chi context value " + k.name
+}
diff --git a/vendor/github.com/go-chi/chi/middleware/compress.go b/vendor/github.com/go-chi/chi/middleware/compress.go
new file mode 100644
index 0000000..d2876d4
--- /dev/null
+++ b/vendor/github.com/go-chi/chi/middleware/compress.go
@@ -0,0 +1,275 @@
+package middleware
+
+import (
+ "bufio"
+ "compress/flate"
+ "compress/gzip"
+ "errors"
+ "io"
+ "net"
+ "net/http"
+ "strings"
+)
+
+var encoders = map[string]EncoderFunc{}
+
+var encodingPrecedence = []string{"br", "gzip", "deflate"}
+
+func init() {
+ // TODO:
+ // lzma: Opera.
+ // sdch: Chrome, Android. Gzip output + dictionary header.
+ // br: Brotli, see https://github.com/go-chi/chi/pull/326
+
+ // TODO: Exception for old MSIE browsers that can't handle non-HTML?
+ // https://zoompf.com/blog/2012/02/lose-the-wait-http-compression
+ SetEncoder("gzip", encoderGzip)
+
+ // HTTP 1.1 "deflate" (RFC 2616) stands for DEFLATE data (RFC 1951)
+ // wrapped with zlib (RFC 1950). The zlib wrapper uses Adler-32
+ // checksum compared to CRC-32 used in "gzip" and thus is faster.
+ //
+ // But.. some old browsers (MSIE, Safari 5.1) incorrectly expect
+ // raw DEFLATE data only, without the mentioned zlib wrapper.
+ // Because of this major confusion, most modern browsers try it
+ // both ways, first looking for zlib headers.
+ // Quote by Mark Adler: http://stackoverflow.com/a/9186091/385548
+ //
+ // The list of browsers having problems is quite big, see:
+ // http://zoompf.com/blog/2012/02/lose-the-wait-http-compression
+ // https://web.archive.org/web/20120321182910/http://www.vervestudios.co/projects/compression-tests/results
+ //
+ // That's why we prefer gzip over deflate. It's just more reliable
+ // and not significantly slower than gzip.
+ SetEncoder("deflate", encoderDeflate)
+
+ // NOTE: Not implemented, intentionally:
+ // case "compress": // LZW. Deprecated.
+ // case "bzip2": // Too slow on-the-fly.
+ // case "zopfli": // Too slow on-the-fly.
+ // case "xz": // Too slow on-the-fly.
+}
+
+// An EncoderFunc is a function that wraps the provided ResponseWriter with a
+// streaming compression algorithm and returns it.
+//
+// In case of failure, the function should return nil.
+type EncoderFunc func(w http.ResponseWriter, level int) io.Writer
+
+// SetEncoder can be used to set the implementation of a compression algorithm.
+//
+// The encoding should be a standardised identifier. See:
+// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Encoding
+//
+// For example, add the Brotli algortithm:
+//
+// import brotli_enc "gopkg.in/kothar/brotli-go.v0/enc"
+//
+// middleware.SetEncoder("br", func(w http.ResponseWriter, level int) io.Writer {
+// params := brotli_enc.NewBrotliParams()
+// params.SetQuality(level)
+// return brotli_enc.NewBrotliWriter(params, w)
+// })
+func SetEncoder(encoding string, fn EncoderFunc) {
+ encoding = strings.ToLower(encoding)
+ if encoding == "" {
+ panic("the encoding can not be empty")
+ }
+ if fn == nil {
+ panic("attempted to set a nil encoder function")
+ }
+ encoders[encoding] = fn
+
+ var e string
+ for _, v := range encodingPrecedence {
+ if v == encoding {
+ e = v
+ }
+ }
+
+ if e == "" {
+ encodingPrecedence = append([]string{e}, encodingPrecedence...)
+ }
+}
+
+var defaultContentTypes = map[string]struct{}{
+ "text/html": {},
+ "text/css": {},
+ "text/plain": {},
+ "text/javascript": {},
+ "application/javascript": {},
+ "application/x-javascript": {},
+ "application/json": {},
+ "application/atom+xml": {},
+ "application/rss+xml": {},
+ "image/svg+xml": {},
+}
+
+// DefaultCompress is a middleware that compresses response
+// body of predefined content types to a data format based
+// on Accept-Encoding request header. It uses a default
+// compression level.
+func DefaultCompress(next http.Handler) http.Handler {
+ return Compress(flate.DefaultCompression)(next)
+}
+
+// Compress is a middleware that compresses response
+// body of a given content types to a data format based
+// on Accept-Encoding request header. It uses a given
+// compression level.
+//
+// NOTE: make sure to set the Content-Type header on your response
+// otherwise this middleware will not compress the response body. For ex, in
+// your handler you should set w.Header().Set("Content-Type", http.DetectContentType(yourBody))
+// or set it manually.
+func Compress(level int, types ...string) func(next http.Handler) http.Handler {
+ contentTypes := defaultContentTypes
+ if len(types) > 0 {
+ contentTypes = make(map[string]struct{}, len(types))
+ for _, t := range types {
+ contentTypes[t] = struct{}{}
+ }
+ }
+
+ return func(next http.Handler) http.Handler {
+ fn := func(w http.ResponseWriter, r *http.Request) {
+ encoder, encoding := selectEncoder(r.Header)
+
+ cw := &compressResponseWriter{
+ ResponseWriter: w,
+ w: w,
+ contentTypes: contentTypes,
+ encoder: encoder,
+ encoding: encoding,
+ level: level,
+ }
+ defer cw.Close()
+
+ next.ServeHTTP(cw, r)
+ }
+
+ return http.HandlerFunc(fn)
+ }
+}
+
+func selectEncoder(h http.Header) (EncoderFunc, string) {
+ header := h.Get("Accept-Encoding")
+
+ // Parse the names of all accepted algorithms from the header.
+ accepted := strings.Split(strings.ToLower(header), ",")
+
+ // Find supported encoder by accepted list by precedence
+ for _, name := range encodingPrecedence {
+ if fn, ok := encoders[name]; ok && matchAcceptEncoding(accepted, name) {
+ return fn, name
+ }
+ }
+
+ // No encoder found to match the accepted encoding
+ return nil, ""
+}
+
+func matchAcceptEncoding(accepted []string, encoding string) bool {
+ for _, v := range accepted {
+ if strings.Index(v, encoding) >= 0 {
+ return true
+ }
+ }
+ return false
+}
+
+type compressResponseWriter struct {
+ http.ResponseWriter
+ w io.Writer
+ encoder EncoderFunc
+ encoding string
+ contentTypes map[string]struct{}
+ level int
+ wroteHeader bool
+}
+
+func (cw *compressResponseWriter) WriteHeader(code int) {
+ if cw.wroteHeader {
+ return
+ }
+ cw.wroteHeader = true
+ defer cw.ResponseWriter.WriteHeader(code)
+
+ // Already compressed data?
+ if cw.Header().Get("Content-Encoding") != "" {
+ return
+ }
+
+ // Parse the first part of the Content-Type response header.
+ contentType := ""
+ parts := strings.Split(cw.Header().Get("Content-Type"), ";")
+ if len(parts) > 0 {
+ contentType = parts[0]
+ }
+
+ // Is the content type compressable?
+ if _, ok := cw.contentTypes[contentType]; !ok {
+ return
+ }
+
+ if cw.encoder != nil && cw.encoding != "" {
+ if wr := cw.encoder(cw.ResponseWriter, cw.level); wr != nil {
+ cw.w = wr
+ cw.Header().Set("Content-Encoding", cw.encoding)
+
+ // The content-length after compression is unknown
+ cw.Header().Del("Content-Length")
+ }
+ }
+}
+
+func (cw *compressResponseWriter) Write(p []byte) (int, error) {
+ if !cw.wroteHeader {
+ cw.WriteHeader(http.StatusOK)
+ }
+
+ return cw.w.Write(p)
+}
+
+func (cw *compressResponseWriter) Flush() {
+ if f, ok := cw.w.(http.Flusher); ok {
+ f.Flush()
+ }
+}
+
+func (cw *compressResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ if hj, ok := cw.w.(http.Hijacker); ok {
+ return hj.Hijack()
+ }
+ return nil, nil, errors.New("chi/middleware: http.Hijacker is unavailable on the writer")
+}
+
+func (cw *compressResponseWriter) Push(target string, opts *http.PushOptions) error {
+ if ps, ok := cw.w.(http.Pusher); ok {
+ return ps.Push(target, opts)
+ }
+ return errors.New("chi/middleware: http.Pusher is unavailable on the writer")
+}
+
+func (cw *compressResponseWriter) Close() error {
+ if c, ok := cw.w.(io.WriteCloser); ok {
+ return c.Close()
+ }
+ return errors.New("chi/middleware: io.WriteCloser is unavailable on the writer")
+}
+
+func encoderGzip(w http.ResponseWriter, level int) io.Writer {
+ gw, err := gzip.NewWriterLevel(w, level)
+ if err != nil {
+ return nil
+ }
+ return gw
+}
+
+func encoderDeflate(w http.ResponseWriter, level int) io.Writer {
+ dw, err := flate.NewWriter(w, level)
+ if err != nil {
+ return nil
+ }
+ return dw
+}
diff --git a/vendor/github.com/go-chi/chi/middleware/content_charset.go b/vendor/github.com/go-chi/chi/middleware/content_charset.go
new file mode 100644
index 0000000..07b5ce6
--- /dev/null
+++ b/vendor/github.com/go-chi/chi/middleware/content_charset.go
@@ -0,0 +1,51 @@
+package middleware
+
+import (
+ "net/http"
+ "strings"
+)
+
+// ContentCharset generates a handler that writes a 415 Unsupported Media Type response if none of the charsets match.
+// An empty charset will allow requests with no Content-Type header or no specified charset.
+func ContentCharset(charsets ...string) func(next http.Handler) http.Handler {
+ for i, c := range charsets {
+ charsets[i] = strings.ToLower(c)
+ }
+
+ return func(next http.Handler) http.Handler {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ if !contentEncoding(r.Header.Get("Content-Type"), charsets...) {
+ w.WriteHeader(http.StatusUnsupportedMediaType)
+ return
+ }
+
+ next.ServeHTTP(w, r)
+ })
+ }
+}
+
+// Check the content encoding against a list of acceptable values.
+func contentEncoding(ce string, charsets ...string) bool {
+ _, ce = split(strings.ToLower(ce), ";")
+ _, ce = split(ce, "charset=")
+ ce, _ = split(ce, ";")
+ for _, c := range charsets {
+ if ce == c {
+ return true
+ }
+ }
+
+ return false
+}
+
+// Split a string in two parts, cleaning any whitespace.
+func split(str, sep string) (string, string) {
+ var a, b string
+ var parts = strings.SplitN(str, sep, 2)
+ a = strings.TrimSpace(parts[0])
+ if len(parts) == 2 {
+ b = strings.TrimSpace(parts[1])
+ }
+
+ return a, b
+}
diff --git a/vendor/github.com/go-chi/chi/middleware/content_type.go b/vendor/github.com/go-chi/chi/middleware/content_type.go
new file mode 100644
index 0000000..ee49578
--- /dev/null
+++ b/vendor/github.com/go-chi/chi/middleware/content_type.go
@@ -0,0 +1,51 @@
+package middleware
+
+import (
+ "net/http"
+ "strings"
+)
+
+// SetHeader is a convenience handler to set a response header key/value
+func SetHeader(key, value string) func(next http.Handler) http.Handler {
+ return func(next http.Handler) http.Handler {
+ fn := func(w http.ResponseWriter, r *http.Request) {
+ w.Header().Set(key, value)
+ next.ServeHTTP(w, r)
+ }
+ return http.HandlerFunc(fn)
+ }
+}
+
+// AllowContentType enforces a whitelist of request Content-Types otherwise responds
+// with a 415 Unsupported Media Type status.
+func AllowContentType(contentTypes ...string) func(next http.Handler) http.Handler {
+ cT := []string{}
+ for _, t := range contentTypes {
+ cT = append(cT, strings.ToLower(t))
+ }
+
+ return func(next http.Handler) http.Handler {
+ fn := func(w http.ResponseWriter, r *http.Request) {
+ if r.ContentLength == 0 {
+ // skip check for empty content body
+ next.ServeHTTP(w, r)
+ return
+ }
+
+ s := strings.ToLower(strings.TrimSpace(r.Header.Get("Content-Type")))
+ if i := strings.Index(s, ";"); i > -1 {
+ s = s[0:i]
+ }
+
+ for _, t := range cT {
+ if t == s {
+ next.ServeHTTP(w, r)
+ return
+ }
+ }
+
+ w.WriteHeader(http.StatusUnsupportedMediaType)
+ }
+ return http.HandlerFunc(fn)
+ }
+}
diff --git a/vendor/github.com/go-chi/chi/middleware/get_head.go b/vendor/github.com/go-chi/chi/middleware/get_head.go
new file mode 100644
index 0000000..86068a9
--- /dev/null
+++ b/vendor/github.com/go-chi/chi/middleware/get_head.go
@@ -0,0 +1,39 @@
+package middleware
+
+import (
+ "net/http"
+
+ "github.com/go-chi/chi"
+)
+
+// GetHead automatically route undefined HEAD requests to GET handlers.
+func GetHead(next http.Handler) http.Handler {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ if r.Method == "HEAD" {
+ rctx := chi.RouteContext(r.Context())
+ routePath := rctx.RoutePath
+ if routePath == "" {
+ if r.URL.RawPath != "" {
+ routePath = r.URL.RawPath
+ } else {
+ routePath = r.URL.Path
+ }
+ }
+
+ // Temporary routing context to look-ahead before routing the request
+ tctx := chi.NewRouteContext()
+
+ // Attempt to find a HEAD handler for the routing path, if not found, traverse
+ // the router as through its a GET route, but proceed with the request
+ // with the HEAD method.
+ if !rctx.Routes.Match(tctx, "HEAD", routePath) {
+ rctx.RouteMethod = "GET"
+ rctx.RoutePath = routePath
+ next.ServeHTTP(w, r)
+ return
+ }
+ }
+
+ next.ServeHTTP(w, r)
+ })
+}
diff --git a/vendor/github.com/go-chi/chi/middleware/heartbeat.go b/vendor/github.com/go-chi/chi/middleware/heartbeat.go
new file mode 100644
index 0000000..fe822fb
--- /dev/null
+++ b/vendor/github.com/go-chi/chi/middleware/heartbeat.go
@@ -0,0 +1,26 @@
+package middleware
+
+import (
+ "net/http"
+ "strings"
+)
+
+// Heartbeat endpoint middleware useful to setting up a path like
+// `/ping` that load balancers or uptime testing external services
+// can make a request before hitting any routes. It's also convenient
+// to place this above ACL middlewares as well.
+func Heartbeat(endpoint string) func(http.Handler) http.Handler {
+ f := func(h http.Handler) http.Handler {
+ fn := func(w http.ResponseWriter, r *http.Request) {
+ if r.Method == "GET" && strings.EqualFold(r.URL.Path, endpoint) {
+ w.Header().Set("Content-Type", "text/plain")
+ w.WriteHeader(http.StatusOK)
+ w.Write([]byte("."))
+ return
+ }
+ h.ServeHTTP(w, r)
+ }
+ return http.HandlerFunc(fn)
+ }
+ return f
+}
diff --git a/vendor/github.com/go-chi/chi/middleware/logger.go b/vendor/github.com/go-chi/chi/middleware/logger.go
new file mode 100644
index 0000000..9f119d5
--- /dev/null
+++ b/vendor/github.com/go-chi/chi/middleware/logger.go
@@ -0,0 +1,158 @@
+package middleware
+
+import (
+ "bytes"
+ "context"
+ "log"
+ "net/http"
+ "os"
+ "time"
+)
+
+var (
+ // LogEntryCtxKey is the context.Context key to store the request log entry.
+ LogEntryCtxKey = &contextKey{"LogEntry"}
+
+ // DefaultLogger is called by the Logger middleware handler to log each request.
+ // Its made a package-level variable so that it can be reconfigured for custom
+ // logging configurations.
+ DefaultLogger = RequestLogger(&DefaultLogFormatter{Logger: log.New(os.Stdout, "", log.LstdFlags), NoColor: false})
+)
+
+// Logger is a middleware that logs the start and end of each request, along
+// with some useful data about what was requested, what the response status was,
+// and how long it took to return. When standard output is a TTY, Logger will
+// print in color, otherwise it will print in black and white. Logger prints a
+// request ID if one is provided.
+//
+// Alternatively, look at https://github.com/pressly/lg and the `lg.RequestLogger`
+// middleware pkg.
+func Logger(next http.Handler) http.Handler {
+ return DefaultLogger(next)
+}
+
+// RequestLogger returns a logger handler using a custom LogFormatter.
+func RequestLogger(f LogFormatter) func(next http.Handler) http.Handler {
+ return func(next http.Handler) http.Handler {
+ fn := func(w http.ResponseWriter, r *http.Request) {
+ entry := f.NewLogEntry(r)
+ ww := NewWrapResponseWriter(w, r.ProtoMajor)
+
+ t1 := time.Now()
+ defer func() {
+ entry.Write(ww.Status(), ww.BytesWritten(), time.Since(t1))
+ }()
+
+ next.ServeHTTP(ww, WithLogEntry(r, entry))
+ }
+ return http.HandlerFunc(fn)
+ }
+}
+
+// LogFormatter initiates the beginning of a new LogEntry per request.
+// See DefaultLogFormatter for an example implementation.
+type LogFormatter interface {
+ NewLogEntry(r *http.Request) LogEntry
+}
+
+// LogEntry records the final log when a request completes.
+// See defaultLogEntry for an example implementation.
+type LogEntry interface {
+ Write(status, bytes int, elapsed time.Duration)
+ Panic(v interface{}, stack []byte)
+}
+
+// GetLogEntry returns the in-context LogEntry for a request.
+func GetLogEntry(r *http.Request) LogEntry {
+ entry, _ := r.Context().Value(LogEntryCtxKey).(LogEntry)
+ return entry
+}
+
+// WithLogEntry sets the in-context LogEntry for a request.
+func WithLogEntry(r *http.Request, entry LogEntry) *http.Request {
+ r = r.WithContext(context.WithValue(r.Context(), LogEntryCtxKey, entry))
+ return r
+}
+
+// LoggerInterface accepts printing to stdlib logger or compatible logger.
+type LoggerInterface interface {
+ Print(v ...interface{})
+}
+
+// DefaultLogFormatter is a simple logger that implements a LogFormatter.
+type DefaultLogFormatter struct {
+ Logger LoggerInterface
+ NoColor bool
+}
+
+// NewLogEntry creates a new LogEntry for the request.
+func (l *DefaultLogFormatter) NewLogEntry(r *http.Request) LogEntry {
+ useColor := !l.NoColor
+ entry := &defaultLogEntry{
+ DefaultLogFormatter: l,
+ request: r,
+ buf: &bytes.Buffer{},
+ useColor: useColor,
+ }
+
+ reqID := GetReqID(r.Context())
+ if reqID != "" {
+ cW(entry.buf, useColor, nYellow, "[%s] ", reqID)
+ }
+ cW(entry.buf, useColor, nCyan, "\"")
+ cW(entry.buf, useColor, bMagenta, "%s ", r.Method)
+
+ scheme := "http"
+ if r.TLS != nil {
+ scheme = "https"
+ }
+ cW(entry.buf, useColor, nCyan, "%s://%s%s %s\" ", scheme, r.Host, r.RequestURI, r.Proto)
+
+ entry.buf.WriteString("from ")
+ entry.buf.WriteString(r.RemoteAddr)
+ entry.buf.WriteString(" - ")
+
+ return entry
+}
+
+type defaultLogEntry struct {
+ *DefaultLogFormatter
+ request *http.Request
+ buf *bytes.Buffer
+ useColor bool
+}
+
+func (l *defaultLogEntry) Write(status, bytes int, elapsed time.Duration) {
+ switch {
+ case status < 200:
+ cW(l.buf, l.useColor, bBlue, "%03d", status)
+ case status < 300:
+ cW(l.buf, l.useColor, bGreen, "%03d", status)
+ case status < 400:
+ cW(l.buf, l.useColor, bCyan, "%03d", status)
+ case status < 500:
+ cW(l.buf, l.useColor, bYellow, "%03d", status)
+ default:
+ cW(l.buf, l.useColor, bRed, "%03d", status)
+ }
+
+ cW(l.buf, l.useColor, bBlue, " %dB", bytes)
+
+ l.buf.WriteString(" in ")
+ if elapsed < 500*time.Millisecond {
+ cW(l.buf, l.useColor, nGreen, "%s", elapsed)
+ } else if elapsed < 5*time.Second {
+ cW(l.buf, l.useColor, nYellow, "%s", elapsed)
+ } else {
+ cW(l.buf, l.useColor, nRed, "%s", elapsed)
+ }
+
+ l.Logger.Print(l.buf.String())
+}
+
+func (l *defaultLogEntry) Panic(v interface{}, stack []byte) {
+ panicEntry := l.NewLogEntry(l.request).(*defaultLogEntry)
+ cW(panicEntry.buf, l.useColor, bRed, "panic: %+v", v)
+ l.Logger.Print(panicEntry.buf.String())
+ l.Logger.Print(string(stack))
+}
diff --git a/vendor/github.com/go-chi/chi/middleware/middleware.go b/vendor/github.com/go-chi/chi/middleware/middleware.go
new file mode 100644
index 0000000..be6a44f
--- /dev/null
+++ b/vendor/github.com/go-chi/chi/middleware/middleware.go
@@ -0,0 +1,12 @@
+package middleware
+
+// contextKey is a value for use with context.WithValue. It's used as
+// a pointer so it fits in an interface{} without allocation. This technique
+// for defining context keys was copied from Go 1.7's new use of context in net/http.
+type contextKey struct {
+ name string
+}
+
+func (k *contextKey) String() string {
+ return "chi/middleware context value " + k.name
+}
diff --git a/vendor/github.com/go-chi/chi/middleware/nocache.go b/vendor/github.com/go-chi/chi/middleware/nocache.go
new file mode 100644
index 0000000..2412829
--- /dev/null
+++ b/vendor/github.com/go-chi/chi/middleware/nocache.go
@@ -0,0 +1,58 @@
+package middleware
+
+// Ported from Goji's middleware, source:
+// https://github.com/zenazn/goji/tree/master/web/middleware
+
+import (
+ "net/http"
+ "time"
+)
+
+// Unix epoch time
+var epoch = time.Unix(0, 0).Format(time.RFC1123)
+
+// Taken from https://github.com/mytrile/nocache
+var noCacheHeaders = map[string]string{
+ "Expires": epoch,
+ "Cache-Control": "no-cache, no-store, no-transform, must-revalidate, private, max-age=0",
+ "Pragma": "no-cache",
+ "X-Accel-Expires": "0",
+}
+
+var etagHeaders = []string{
+ "ETag",
+ "If-Modified-Since",
+ "If-Match",
+ "If-None-Match",
+ "If-Range",
+ "If-Unmodified-Since",
+}
+
+// NoCache is a simple piece of middleware that sets a number of HTTP headers to prevent
+// a router (or subrouter) from being cached by an upstream proxy and/or client.
+//
+// As per http://wiki.nginx.org/HttpProxyModule - NoCache sets:
+// Expires: Thu, 01 Jan 1970 00:00:00 UTC
+// Cache-Control: no-cache, private, max-age=0
+// X-Accel-Expires: 0
+// Pragma: no-cache (for HTTP/1.0 proxies/clients)
+func NoCache(h http.Handler) http.Handler {
+ fn := func(w http.ResponseWriter, r *http.Request) {
+
+ // Delete any ETag headers that may have been set
+ for _, v := range etagHeaders {
+ if r.Header.Get(v) != "" {
+ r.Header.Del(v)
+ }
+ }
+
+ // Set our NoCache headers
+ for k, v := range noCacheHeaders {
+ w.Header().Set(k, v)
+ }
+
+ h.ServeHTTP(w, r)
+ }
+
+ return http.HandlerFunc(fn)
+}
diff --git a/vendor/github.com/go-chi/chi/middleware/profiler.go b/vendor/github.com/go-chi/chi/middleware/profiler.go
new file mode 100644
index 0000000..1d44b82
--- /dev/null
+++ b/vendor/github.com/go-chi/chi/middleware/profiler.go
@@ -0,0 +1,55 @@
+package middleware
+
+import (
+ "expvar"
+ "fmt"
+ "net/http"
+ "net/http/pprof"
+
+ "github.com/go-chi/chi"
+)
+
+// Profiler is a convenient subrouter used for mounting net/http/pprof. ie.
+//
+// func MyService() http.Handler {
+// r := chi.NewRouter()
+// // ..middlewares
+// r.Mount("/debug", middleware.Profiler())
+// // ..routes
+// return r
+// }
+func Profiler() http.Handler {
+ r := chi.NewRouter()
+ r.Use(NoCache)
+
+ r.Get("/", func(w http.ResponseWriter, r *http.Request) {
+ http.Redirect(w, r, r.RequestURI+"/pprof/", 301)
+ })
+ r.HandleFunc("/pprof", func(w http.ResponseWriter, r *http.Request) {
+ http.Redirect(w, r, r.RequestURI+"/", 301)
+ })
+
+ r.HandleFunc("/pprof/*", pprof.Index)
+ r.HandleFunc("/pprof/cmdline", pprof.Cmdline)
+ r.HandleFunc("/pprof/profile", pprof.Profile)
+ r.HandleFunc("/pprof/symbol", pprof.Symbol)
+ r.HandleFunc("/pprof/trace", pprof.Trace)
+ r.HandleFunc("/vars", expVars)
+
+ return r
+}
+
+// Replicated from expvar.go as not public.
+func expVars(w http.ResponseWriter, r *http.Request) {
+ first := true
+ w.Header().Set("Content-Type", "application/json")
+ fmt.Fprintf(w, "{\n")
+ expvar.Do(func(kv expvar.KeyValue) {
+ if !first {
+ fmt.Fprintf(w, ",\n")
+ }
+ first = false
+ fmt.Fprintf(w, "%q: %s", kv.Key, kv.Value)
+ })
+ fmt.Fprintf(w, "\n}\n")
+}
diff --git a/vendor/github.com/go-chi/chi/middleware/realip.go b/vendor/github.com/go-chi/chi/middleware/realip.go
new file mode 100644
index 0000000..146c2b0
--- /dev/null
+++ b/vendor/github.com/go-chi/chi/middleware/realip.go
@@ -0,0 +1,54 @@
+package middleware
+
+// Ported from Goji's middleware, source:
+// https://github.com/zenazn/goji/tree/master/web/middleware
+
+import (
+ "net/http"
+ "strings"
+)
+
+var xForwardedFor = http.CanonicalHeaderKey("X-Forwarded-For")
+var xRealIP = http.CanonicalHeaderKey("X-Real-IP")
+
+// RealIP is a middleware that sets a http.Request's RemoteAddr to the results
+// of parsing either the X-Forwarded-For header or the X-Real-IP header (in that
+// order).
+//
+// This middleware should be inserted fairly early in the middleware stack to
+// ensure that subsequent layers (e.g., request loggers) which examine the
+// RemoteAddr will see the intended value.
+//
+// You should only use this middleware if you can trust the headers passed to
+// you (in particular, the two headers this middleware uses), for example
+// because you have placed a reverse proxy like HAProxy or nginx in front of
+// chi. If your reverse proxies are configured to pass along arbitrary header
+// values from the client, or if you use this middleware without a reverse
+// proxy, malicious clients will be able to make you very sad (or, depending on
+// how you're using RemoteAddr, vulnerable to an attack of some sort).
+func RealIP(h http.Handler) http.Handler {
+ fn := func(w http.ResponseWriter, r *http.Request) {
+ if rip := realIP(r); rip != "" {
+ r.RemoteAddr = rip
+ }
+ h.ServeHTTP(w, r)
+ }
+
+ return http.HandlerFunc(fn)
+}
+
+func realIP(r *http.Request) string {
+ var ip string
+
+ if xff := r.Header.Get(xForwardedFor); xff != "" {
+ i := strings.Index(xff, ", ")
+ if i == -1 {
+ i = len(xff)
+ }
+ ip = xff[:i]
+ } else if xrip := r.Header.Get(xRealIP); xrip != "" {
+ ip = xrip
+ }
+
+ return ip
+}
diff --git a/vendor/github.com/go-chi/chi/middleware/recoverer.go b/vendor/github.com/go-chi/chi/middleware/recoverer.go
new file mode 100644
index 0000000..57fc3eb
--- /dev/null
+++ b/vendor/github.com/go-chi/chi/middleware/recoverer.go
@@ -0,0 +1,39 @@
+package middleware
+
+// The original work was derived from Goji's middleware, source:
+// https://github.com/zenazn/goji/tree/master/web/middleware
+
+import (
+ "fmt"
+ "net/http"
+ "os"
+ "runtime/debug"
+)
+
+// Recoverer is a middleware that recovers from panics, logs the panic (and a
+// backtrace), and returns a HTTP 500 (Internal Server Error) status if
+// possible. Recoverer prints a request ID if one is provided.
+//
+// Alternatively, look at https://github.com/pressly/lg middleware pkgs.
+func Recoverer(next http.Handler) http.Handler {
+ fn := func(w http.ResponseWriter, r *http.Request) {
+ defer func() {
+ if rvr := recover(); rvr != nil {
+
+ logEntry := GetLogEntry(r)
+ if logEntry != nil {
+ logEntry.Panic(rvr, debug.Stack())
+ } else {
+ fmt.Fprintf(os.Stderr, "Panic: %+v\n", rvr)
+ debug.PrintStack()
+ }
+
+ http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
+ }
+ }()
+
+ next.ServeHTTP(w, r)
+ }
+
+ return http.HandlerFunc(fn)
+}
diff --git a/vendor/github.com/go-chi/chi/middleware/request_id.go b/vendor/github.com/go-chi/chi/middleware/request_id.go
new file mode 100644
index 0000000..65b58f6
--- /dev/null
+++ b/vendor/github.com/go-chi/chi/middleware/request_id.go
@@ -0,0 +1,92 @@
+package middleware
+
+// Ported from Goji's middleware, source:
+// https://github.com/zenazn/goji/tree/master/web/middleware
+
+import (
+ "context"
+ "crypto/rand"
+ "encoding/base64"
+ "fmt"
+ "net/http"
+ "os"
+ "strings"
+ "sync/atomic"
+)
+
+// Key to use when setting the request ID.
+type ctxKeyRequestID int
+
+// RequestIDKey is the key that holds the unique request ID in a request context.
+const RequestIDKey ctxKeyRequestID = 0
+
+var prefix string
+var reqid uint64
+
+// A quick note on the statistics here: we're trying to calculate the chance that
+// two randomly generated base62 prefixes will collide. We use the formula from
+// http://en.wikipedia.org/wiki/Birthday_problem
+//
+// P[m, n] \approx 1 - e^{-m^2/2n}
+//
+// We ballpark an upper bound for $m$ by imagining (for whatever reason) a server
+// that restarts every second over 10 years, for $m = 86400 * 365 * 10 = 315360000$
+//
+// For a $k$ character base-62 identifier, we have $n(k) = 62^k$
+//
+// Plugging this in, we find $P[m, n(10)] \approx 5.75%$, which is good enough for
+// our purposes, and is surely more than anyone would ever need in practice -- a
+// process that is rebooted a handful of times a day for a hundred years has less
+// than a millionth of a percent chance of generating two colliding IDs.
+
+func init() {
+ hostname, err := os.Hostname()
+ if hostname == "" || err != nil {
+ hostname = "localhost"
+ }
+ var buf [12]byte
+ var b64 string
+ for len(b64) < 10 {
+ rand.Read(buf[:])
+ b64 = base64.StdEncoding.EncodeToString(buf[:])
+ b64 = strings.NewReplacer("+", "", "/", "").Replace(b64)
+ }
+
+ prefix = fmt.Sprintf("%s/%s", hostname, b64[0:10])
+}
+
+// RequestID is a middleware that injects a request ID into the context of each
+// request. A request ID is a string of the form "host.example.com/random-0001",
+// where "random" is a base62 random string that uniquely identifies this go
+// process, and where the last number is an atomically incremented request
+// counter.
+func RequestID(next http.Handler) http.Handler {
+ fn := func(w http.ResponseWriter, r *http.Request) {
+ ctx := r.Context()
+ requestID := r.Header.Get("X-Request-Id")
+ if requestID == "" {
+ myid := atomic.AddUint64(&reqid, 1)
+ requestID = fmt.Sprintf("%s-%06d", prefix, myid)
+ }
+ ctx = context.WithValue(ctx, RequestIDKey, requestID)
+ next.ServeHTTP(w, r.WithContext(ctx))
+ }
+ return http.HandlerFunc(fn)
+}
+
+// GetReqID returns a request ID from the given context if one is present.
+// Returns the empty string if a request ID cannot be found.
+func GetReqID(ctx context.Context) string {
+ if ctx == nil {
+ return ""
+ }
+ if reqID, ok := ctx.Value(RequestIDKey).(string); ok {
+ return reqID
+ }
+ return ""
+}
+
+// NextRequestID generates the next request ID in the sequence.
+func NextRequestID() uint64 {
+ return atomic.AddUint64(&reqid, 1)
+}
diff --git a/vendor/github.com/go-chi/chi/middleware/strip.go b/vendor/github.com/go-chi/chi/middleware/strip.go
new file mode 100644
index 0000000..2b8b184
--- /dev/null
+++ b/vendor/github.com/go-chi/chi/middleware/strip.go
@@ -0,0 +1,56 @@
+package middleware
+
+import (
+ "fmt"
+ "net/http"
+
+ "github.com/go-chi/chi"
+)
+
+// StripSlashes is a middleware that will match request paths with a trailing
+// slash, strip it from the path and continue routing through the mux, if a route
+// matches, then it will serve the handler.
+func StripSlashes(next http.Handler) http.Handler {
+ fn := func(w http.ResponseWriter, r *http.Request) {
+ var path string
+ rctx := chi.RouteContext(r.Context())
+ if rctx.RoutePath != "" {
+ path = rctx.RoutePath
+ } else {
+ path = r.URL.Path
+ }
+ if len(path) > 1 && path[len(path)-1] == '/' {
+ rctx.RoutePath = path[:len(path)-1]
+ }
+ next.ServeHTTP(w, r)
+ }
+ return http.HandlerFunc(fn)
+}
+
+// RedirectSlashes is a middleware that will match request paths with a trailing
+// slash and redirect to the same path, less the trailing slash.
+//
+// NOTE: RedirectSlashes middleware is *incompatible* with http.FileServer,
+// see https://github.com/go-chi/chi/issues/343
+func RedirectSlashes(next http.Handler) http.Handler {
+ fn := func(w http.ResponseWriter, r *http.Request) {
+ var path string
+ rctx := chi.RouteContext(r.Context())
+ if rctx.RoutePath != "" {
+ path = rctx.RoutePath
+ } else {
+ path = r.URL.Path
+ }
+ if len(path) > 1 && path[len(path)-1] == '/' {
+ if r.URL.RawQuery != "" {
+ path = fmt.Sprintf("%s?%s", path[:len(path)-1], r.URL.RawQuery)
+ } else {
+ path = path[:len(path)-1]
+ }
+ http.Redirect(w, r, path, 301)
+ return
+ }
+ next.ServeHTTP(w, r)
+ }
+ return http.HandlerFunc(fn)
+}
diff --git a/vendor/github.com/go-chi/chi/middleware/terminal.go b/vendor/github.com/go-chi/chi/middleware/terminal.go
new file mode 100644
index 0000000..a5d4241
--- /dev/null
+++ b/vendor/github.com/go-chi/chi/middleware/terminal.go
@@ -0,0 +1,63 @@
+package middleware
+
+// Ported from Goji's middleware, source:
+// https://github.com/zenazn/goji/tree/master/web/middleware
+
+import (
+ "fmt"
+ "io"
+ "os"
+)
+
+var (
+ // Normal colors
+ nBlack = []byte{'\033', '[', '3', '0', 'm'}
+ nRed = []byte{'\033', '[', '3', '1', 'm'}
+ nGreen = []byte{'\033', '[', '3', '2', 'm'}
+ nYellow = []byte{'\033', '[', '3', '3', 'm'}
+ nBlue = []byte{'\033', '[', '3', '4', 'm'}
+ nMagenta = []byte{'\033', '[', '3', '5', 'm'}
+ nCyan = []byte{'\033', '[', '3', '6', 'm'}
+ nWhite = []byte{'\033', '[', '3', '7', 'm'}
+ // Bright colors
+ bBlack = []byte{'\033', '[', '3', '0', ';', '1', 'm'}
+ bRed = []byte{'\033', '[', '3', '1', ';', '1', 'm'}
+ bGreen = []byte{'\033', '[', '3', '2', ';', '1', 'm'}
+ bYellow = []byte{'\033', '[', '3', '3', ';', '1', 'm'}
+ bBlue = []byte{'\033', '[', '3', '4', ';', '1', 'm'}
+ bMagenta = []byte{'\033', '[', '3', '5', ';', '1', 'm'}
+ bCyan = []byte{'\033', '[', '3', '6', ';', '1', 'm'}
+ bWhite = []byte{'\033', '[', '3', '7', ';', '1', 'm'}
+
+ reset = []byte{'\033', '[', '0', 'm'}
+)
+
+var isTTY bool
+
+func init() {
+ // This is sort of cheating: if stdout is a character device, we assume
+ // that means it's a TTY. Unfortunately, there are many non-TTY
+ // character devices, but fortunately stdout is rarely set to any of
+ // them.
+ //
+ // We could solve this properly by pulling in a dependency on
+ // code.google.com/p/go.crypto/ssh/terminal, for instance, but as a
+ // heuristic for whether to print in color or in black-and-white, I'd
+ // really rather not.
+ fi, err := os.Stdout.Stat()
+ if err == nil {
+ m := os.ModeDevice | os.ModeCharDevice
+ isTTY = fi.Mode()&m == m
+ }
+}
+
+// colorWrite
+func cW(w io.Writer, useColor bool, color []byte, s string, args ...interface{}) {
+ if isTTY && useColor {
+ w.Write(color)
+ }
+ fmt.Fprintf(w, s, args...)
+ if isTTY && useColor {
+ w.Write(reset)
+ }
+}
diff --git a/vendor/github.com/go-chi/chi/middleware/throttle.go b/vendor/github.com/go-chi/chi/middleware/throttle.go
new file mode 100644
index 0000000..d935e2c
--- /dev/null
+++ b/vendor/github.com/go-chi/chi/middleware/throttle.go
@@ -0,0 +1,101 @@
+package middleware
+
+import (
+ "net/http"
+ "time"
+)
+
+const (
+ errCapacityExceeded = "Server capacity exceeded."
+ errTimedOut = "Timed out while waiting for a pending request to complete."
+ errContextCanceled = "Context was canceled."
+)
+
+var (
+ defaultBacklogTimeout = time.Second * 60
+)
+
+// Throttle is a middleware that limits number of currently processed requests
+// at a time.
+func Throttle(limit int) func(http.Handler) http.Handler {
+ return ThrottleBacklog(limit, 0, defaultBacklogTimeout)
+}
+
+// ThrottleBacklog is a middleware that limits number of currently processed
+// requests at a time and provides a backlog for holding a finite number of
+// pending requests.
+func ThrottleBacklog(limit int, backlogLimit int, backlogTimeout time.Duration) func(http.Handler) http.Handler {
+ if limit < 1 {
+ panic("chi/middleware: Throttle expects limit > 0")
+ }
+
+ if backlogLimit < 0 {
+ panic("chi/middleware: Throttle expects backlogLimit to be positive")
+ }
+
+ t := throttler{
+ tokens: make(chan token, limit),
+ backlogTokens: make(chan token, limit+backlogLimit),
+ backlogTimeout: backlogTimeout,
+ }
+
+ // Filling tokens.
+ for i := 0; i < limit+backlogLimit; i++ {
+ if i < limit {
+ t.tokens <- token{}
+ }
+ t.backlogTokens <- token{}
+ }
+
+ fn := func(h http.Handler) http.Handler {
+ t.h = h
+ return &t
+ }
+
+ return fn
+}
+
+// token represents a request that is being processed.
+type token struct{}
+
+// throttler limits number of currently processed requests at a time.
+type throttler struct {
+ h http.Handler
+ tokens chan token
+ backlogTokens chan token
+ backlogTimeout time.Duration
+}
+
+// ServeHTTP is the primary throttler request handler
+func (t *throttler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+ ctx := r.Context()
+ select {
+ case <-ctx.Done():
+ http.Error(w, errContextCanceled, http.StatusServiceUnavailable)
+ return
+ case btok := <-t.backlogTokens:
+ timer := time.NewTimer(t.backlogTimeout)
+
+ defer func() {
+ t.backlogTokens <- btok
+ }()
+
+ select {
+ case <-timer.C:
+ http.Error(w, errTimedOut, http.StatusServiceUnavailable)
+ return
+ case <-ctx.Done():
+ http.Error(w, errContextCanceled, http.StatusServiceUnavailable)
+ return
+ case tok := <-t.tokens:
+ defer func() {
+ t.tokens <- tok
+ }()
+ t.h.ServeHTTP(w, r)
+ }
+ return
+ default:
+ http.Error(w, errCapacityExceeded, http.StatusServiceUnavailable)
+ return
+ }
+}
diff --git a/vendor/github.com/go-chi/chi/middleware/timeout.go b/vendor/github.com/go-chi/chi/middleware/timeout.go
new file mode 100644
index 0000000..8e37353
--- /dev/null
+++ b/vendor/github.com/go-chi/chi/middleware/timeout.go
@@ -0,0 +1,49 @@
+package middleware
+
+import (
+ "context"
+ "net/http"
+ "time"
+)
+
+// Timeout is a middleware that cancels ctx after a given timeout and return
+// a 504 Gateway Timeout error to the client.
+//
+// It's required that you select the ctx.Done() channel to check for the signal
+// if the context has reached its deadline and return, otherwise the timeout
+// signal will be just ignored.
+//
+// ie. a route/handler may look like:
+//
+// r.Get("/long", func(w http.ResponseWriter, r *http.Request) {
+// ctx := r.Context()
+// processTime := time.Duration(rand.Intn(4)+1) * time.Second
+//
+// select {
+// case <-ctx.Done():
+// return
+//
+// case <-time.After(processTime):
+// // The above channel simulates some hard work.
+// }
+//
+// w.Write([]byte("done"))
+// })
+//
+func Timeout(timeout time.Duration) func(next http.Handler) http.Handler {
+ return func(next http.Handler) http.Handler {
+ fn := func(w http.ResponseWriter, r *http.Request) {
+ ctx, cancel := context.WithTimeout(r.Context(), timeout)
+ defer func() {
+ cancel()
+ if ctx.Err() == context.DeadlineExceeded {
+ w.WriteHeader(http.StatusGatewayTimeout)
+ }
+ }()
+
+ r = r.WithContext(ctx)
+ next.ServeHTTP(w, r)
+ }
+ return http.HandlerFunc(fn)
+ }
+}
diff --git a/vendor/github.com/go-chi/chi/middleware/url_format.go b/vendor/github.com/go-chi/chi/middleware/url_format.go
new file mode 100644
index 0000000..5749e4f
--- /dev/null
+++ b/vendor/github.com/go-chi/chi/middleware/url_format.go
@@ -0,0 +1,72 @@
+package middleware
+
+import (
+ "context"
+ "net/http"
+ "strings"
+
+ "github.com/go-chi/chi"
+)
+
+var (
+ // URLFormatCtxKey is the context.Context key to store the URL format data
+ // for a request.
+ URLFormatCtxKey = &contextKey{"URLFormat"}
+)
+
+// URLFormat is a middleware that parses the url extension from a request path and stores it
+// on the context as a string under the key `middleware.URLFormatCtxKey`. The middleware will
+// trim the suffix from the routing path and continue routing.
+//
+// Routers should not include a url parameter for the suffix when using this middleware.
+//
+// Sample usage.. for url paths: `/articles/1`, `/articles/1.json` and `/articles/1.xml`
+//
+// func routes() http.Handler {
+// r := chi.NewRouter()
+// r.Use(middleware.URLFormat)
+//
+// r.Get("/articles/{id}", ListArticles)
+//
+// return r
+// }
+//
+// func ListArticles(w http.ResponseWriter, r *http.Request) {
+// urlFormat, _ := r.Context().Value(middleware.URLFormatCtxKey).(string)
+//
+// switch urlFormat {
+// case "json":
+// render.JSON(w, r, articles)
+// case "xml:"
+// render.XML(w, r, articles)
+// default:
+// render.JSON(w, r, articles)
+// }
+// }
+//
+func URLFormat(next http.Handler) http.Handler {
+ fn := func(w http.ResponseWriter, r *http.Request) {
+ ctx := r.Context()
+
+ var format string
+ path := r.URL.Path
+
+ if strings.Index(path, ".") > 0 {
+ base := strings.LastIndex(path, "/")
+ idx := strings.Index(path[base:], ".")
+
+ if idx > 0 {
+ idx += base
+ format = path[idx+1:]
+
+ rctx := chi.RouteContext(r.Context())
+ rctx.RoutePath = path[:idx]
+ }
+ }
+
+ r = r.WithContext(context.WithValue(ctx, URLFormatCtxKey, format))
+
+ next.ServeHTTP(w, r)
+ }
+ return http.HandlerFunc(fn)
+}
diff --git a/vendor/github.com/go-chi/chi/middleware/value.go b/vendor/github.com/go-chi/chi/middleware/value.go
new file mode 100644
index 0000000..fbbd039
--- /dev/null
+++ b/vendor/github.com/go-chi/chi/middleware/value.go
@@ -0,0 +1,17 @@
+package middleware
+
+import (
+ "context"
+ "net/http"
+)
+
+// WithValue is a middleware that sets a given key/value in a context chain.
+func WithValue(key interface{}, val interface{}) func(next http.Handler) http.Handler {
+ return func(next http.Handler) http.Handler {
+ fn := func(w http.ResponseWriter, r *http.Request) {
+ r = r.WithContext(context.WithValue(r.Context(), key, val))
+ next.ServeHTTP(w, r)
+ }
+ return http.HandlerFunc(fn)
+ }
+}
diff --git a/vendor/github.com/go-chi/chi/middleware/wrap_writer.go b/vendor/github.com/go-chi/chi/middleware/wrap_writer.go
new file mode 100644
index 0000000..5e5594f
--- /dev/null
+++ b/vendor/github.com/go-chi/chi/middleware/wrap_writer.go
@@ -0,0 +1,183 @@
+package middleware
+
+// The original work was derived from Goji's middleware, source:
+// https://github.com/zenazn/goji/tree/master/web/middleware
+
+import (
+ "bufio"
+ "io"
+ "net"
+ "net/http"
+)
+
+// NewWrapResponseWriter wraps an http.ResponseWriter, returning a proxy that allows you to
+// hook into various parts of the response process.
+func NewWrapResponseWriter(w http.ResponseWriter, protoMajor int) WrapResponseWriter {
+ _, fl := w.(http.Flusher)
+
+ bw := basicWriter{ResponseWriter: w}
+
+ if protoMajor == 2 {
+ _, ps := w.(http.Pusher)
+ if fl && ps {
+ return &http2FancyWriter{bw}
+ }
+ } else {
+ _, hj := w.(http.Hijacker)
+ _, rf := w.(io.ReaderFrom)
+ if fl && hj && rf {
+ return &httpFancyWriter{bw}
+ }
+ }
+ if fl {
+ return &flushWriter{bw}
+ }
+
+ return &bw
+}
+
+// WrapResponseWriter is a proxy around an http.ResponseWriter that allows you to hook
+// into various parts of the response process.
+type WrapResponseWriter interface {
+ http.ResponseWriter
+ // Status returns the HTTP status of the request, or 0 if one has not
+ // yet been sent.
+ Status() int
+ // BytesWritten returns the total number of bytes sent to the client.
+ BytesWritten() int
+ // Tee causes the response body to be written to the given io.Writer in
+ // addition to proxying the writes through. Only one io.Writer can be
+ // tee'd to at once: setting a second one will overwrite the first.
+ // Writes will be sent to the proxy before being written to this
+ // io.Writer. It is illegal for the tee'd writer to be modified
+ // concurrently with writes.
+ Tee(io.Writer)
+ // Unwrap returns the original proxied target.
+ Unwrap() http.ResponseWriter
+}
+
+// basicWriter wraps a http.ResponseWriter that implements the minimal
+// http.ResponseWriter interface.
+type basicWriter struct {
+ http.ResponseWriter
+ wroteHeader bool
+ code int
+ bytes int
+ tee io.Writer
+}
+
+func (b *basicWriter) WriteHeader(code int) {
+ if !b.wroteHeader {
+ b.code = code
+ b.wroteHeader = true
+ b.ResponseWriter.WriteHeader(code)
+ }
+}
+
+func (b *basicWriter) Write(buf []byte) (int, error) {
+ b.WriteHeader(http.StatusOK)
+ n, err := b.ResponseWriter.Write(buf)
+ if b.tee != nil {
+ _, err2 := b.tee.Write(buf[:n])
+ // Prefer errors generated by the proxied writer.
+ if err == nil {
+ err = err2
+ }
+ }
+ b.bytes += n
+ return n, err
+}
+
+func (b *basicWriter) maybeWriteHeader() {
+ if !b.wroteHeader {
+ b.WriteHeader(http.StatusOK)
+ }
+}
+
+func (b *basicWriter) Status() int {
+ return b.code
+}
+
+func (b *basicWriter) BytesWritten() int {
+ return b.bytes
+}
+
+func (b *basicWriter) Tee(w io.Writer) {
+ b.tee = w
+}
+
+func (b *basicWriter) Unwrap() http.ResponseWriter {
+ return b.ResponseWriter
+}
+
+type flushWriter struct {
+ basicWriter
+}
+
+func (f *flushWriter) Flush() {
+ f.wroteHeader = true
+
+ fl := f.basicWriter.ResponseWriter.(http.Flusher)
+ fl.Flush()
+}
+
+var _ http.Flusher = &flushWriter{}
+
+// httpFancyWriter is a HTTP writer that additionally satisfies
+// http.Flusher, http.Hijacker, and io.ReaderFrom. It exists for the common case
+// of wrapping the http.ResponseWriter that package http gives you, in order to
+// make the proxied object support the full method set of the proxied object.
+type httpFancyWriter struct {
+ basicWriter
+}
+
+func (f *httpFancyWriter) Flush() {
+ f.wroteHeader = true
+
+ fl := f.basicWriter.ResponseWriter.(http.Flusher)
+ fl.Flush()
+}
+
+func (f *httpFancyWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+ hj := f.basicWriter.ResponseWriter.(http.Hijacker)
+ return hj.Hijack()
+}
+
+func (f *http2FancyWriter) Push(target string, opts *http.PushOptions) error {
+ return f.basicWriter.ResponseWriter.(http.Pusher).Push(target, opts)
+}
+
+func (f *httpFancyWriter) ReadFrom(r io.Reader) (int64, error) {
+ if f.basicWriter.tee != nil {
+ n, err := io.Copy(&f.basicWriter, r)
+ f.basicWriter.bytes += int(n)
+ return n, err
+ }
+ rf := f.basicWriter.ResponseWriter.(io.ReaderFrom)
+ f.basicWriter.maybeWriteHeader()
+ n, err := rf.ReadFrom(r)
+ f.basicWriter.bytes += int(n)
+ return n, err
+}
+
+var _ http.Flusher = &httpFancyWriter{}
+var _ http.Hijacker = &httpFancyWriter{}
+var _ http.Pusher = &http2FancyWriter{}
+var _ io.ReaderFrom = &httpFancyWriter{}
+
+// http2FancyWriter is a HTTP2 writer that additionally satisfies
+// http.Flusher, and io.ReaderFrom. It exists for the common case
+// of wrapping the http.ResponseWriter that package http gives you, in order to
+// make the proxied object support the full method set of the proxied object.
+type http2FancyWriter struct {
+ basicWriter
+}
+
+func (f *http2FancyWriter) Flush() {
+ f.wroteHeader = true
+
+ fl := f.basicWriter.ResponseWriter.(http.Flusher)
+ fl.Flush()
+}
+
+var _ http.Flusher = &http2FancyWriter{}
diff --git a/vendor/github.com/go-chi/chi/mux.go b/vendor/github.com/go-chi/chi/mux.go
new file mode 100644
index 0000000..e553287
--- /dev/null
+++ b/vendor/github.com/go-chi/chi/mux.go
@@ -0,0 +1,460 @@
+package chi
+
+import (
+ "context"
+ "fmt"
+ "net/http"
+ "strings"
+ "sync"
+)
+
+var _ Router = &Mux{}
+
+// Mux is a simple HTTP route multiplexer that parses a request path,
+// records any URL params, and executes an end handler. It implements
+// the http.Handler interface and is friendly with the standard library.
+//
+// Mux is designed to be fast, minimal and offer a powerful API for building
+// modular and composable HTTP services with a large set of handlers. It's
+// particularly useful for writing large REST API services that break a handler
+// into many smaller parts composed of middlewares and end handlers.
+type Mux struct {
+ // The radix trie router
+ tree *node
+
+ // The middleware stack
+ middlewares []func(http.Handler) http.Handler
+
+ // Controls the behaviour of middleware chain generation when a mux
+ // is registered as an inline group inside another mux.
+ inline bool
+ parent *Mux
+
+ // The computed mux handler made of the chained middleware stack and
+ // the tree router
+ handler http.Handler
+
+ // Routing context pool
+ pool *sync.Pool
+
+ // Custom route not found handler
+ notFoundHandler http.HandlerFunc
+
+ // Custom method not allowed handler
+ methodNotAllowedHandler http.HandlerFunc
+}
+
+// NewMux returns a newly initialized Mux object that implements the Router
+// interface.
+func NewMux() *Mux {
+ mux := &Mux{tree: &node{}, pool: &sync.Pool{}}
+ mux.pool.New = func() interface{} {
+ return NewRouteContext()
+ }
+ return mux
+}
+
+// ServeHTTP is the single method of the http.Handler interface that makes
+// Mux interoperable with the standard library. It uses a sync.Pool to get and
+// reuse routing contexts for each request.
+func (mx *Mux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+ // Ensure the mux has some routes defined on the mux
+ if mx.handler == nil {
+ mx.NotFoundHandler().ServeHTTP(w, r)
+ return
+ }
+
+ // Check if a routing context already exists from a parent router.
+ rctx, _ := r.Context().Value(RouteCtxKey).(*Context)
+ if rctx != nil {
+ mx.handler.ServeHTTP(w, r)
+ return
+ }
+
+ // Fetch a RouteContext object from the sync pool, and call the computed
+ // mx.handler that is comprised of mx.middlewares + mx.routeHTTP.
+ // Once the request is finished, reset the routing context and put it back
+ // into the pool for reuse from another request.
+ rctx = mx.pool.Get().(*Context)
+ rctx.Reset()
+ rctx.Routes = mx
+ r = r.WithContext(context.WithValue(r.Context(), RouteCtxKey, rctx))
+ mx.handler.ServeHTTP(w, r)
+ mx.pool.Put(rctx)
+}
+
+// Use appends a middleware handler to the Mux middleware stack.
+//
+// The middleware stack for any Mux will execute before searching for a matching
+// route to a specific handler, which provides opportunity to respond early,
+// change the course of the request execution, or set request-scoped values for
+// the next http.Handler.
+func (mx *Mux) Use(middlewares ...func(http.Handler) http.Handler) {
+ if mx.handler != nil {
+ panic("chi: all middlewares must be defined before routes on a mux")
+ }
+ mx.middlewares = append(mx.middlewares, middlewares...)
+}
+
+// Handle adds the route `pattern` that matches any http method to
+// execute the `handler` http.Handler.
+func (mx *Mux) Handle(pattern string, handler http.Handler) {
+ mx.handle(mALL, pattern, handler)
+}
+
+// HandleFunc adds the route `pattern` that matches any http method to
+// execute the `handlerFn` http.HandlerFunc.
+func (mx *Mux) HandleFunc(pattern string, handlerFn http.HandlerFunc) {
+ mx.handle(mALL, pattern, handlerFn)
+}
+
+// Method adds the route `pattern` that matches `method` http method to
+// execute the `handler` http.Handler.
+func (mx *Mux) Method(method, pattern string, handler http.Handler) {
+ m, ok := methodMap[strings.ToUpper(method)]
+ if !ok {
+ panic(fmt.Sprintf("chi: '%s' http method is not supported.", method))
+ }
+ mx.handle(m, pattern, handler)
+}
+
+// MethodFunc adds the route `pattern` that matches `method` http method to
+// execute the `handlerFn` http.HandlerFunc.
+func (mx *Mux) MethodFunc(method, pattern string, handlerFn http.HandlerFunc) {
+ mx.Method(method, pattern, handlerFn)
+}
+
+// Connect adds the route `pattern` that matches a CONNECT http method to
+// execute the `handlerFn` http.HandlerFunc.
+func (mx *Mux) Connect(pattern string, handlerFn http.HandlerFunc) {
+ mx.handle(mCONNECT, pattern, handlerFn)
+}
+
+// Delete adds the route `pattern` that matches a DELETE http method to
+// execute the `handlerFn` http.HandlerFunc.
+func (mx *Mux) Delete(pattern string, handlerFn http.HandlerFunc) {
+ mx.handle(mDELETE, pattern, handlerFn)
+}
+
+// Get adds the route `pattern` that matches a GET http method to
+// execute the `handlerFn` http.HandlerFunc.
+func (mx *Mux) Get(pattern string, handlerFn http.HandlerFunc) {
+ mx.handle(mGET, pattern, handlerFn)
+}
+
+// Head adds the route `pattern` that matches a HEAD http method to
+// execute the `handlerFn` http.HandlerFunc.
+func (mx *Mux) Head(pattern string, handlerFn http.HandlerFunc) {
+ mx.handle(mHEAD, pattern, handlerFn)
+}
+
+// Options adds the route `pattern` that matches a OPTIONS http method to
+// execute the `handlerFn` http.HandlerFunc.
+func (mx *Mux) Options(pattern string, handlerFn http.HandlerFunc) {
+ mx.handle(mOPTIONS, pattern, handlerFn)
+}
+
+// Patch adds the route `pattern` that matches a PATCH http method to
+// execute the `handlerFn` http.HandlerFunc.
+func (mx *Mux) Patch(pattern string, handlerFn http.HandlerFunc) {
+ mx.handle(mPATCH, pattern, handlerFn)
+}
+
+// Post adds the route `pattern` that matches a POST http method to
+// execute the `handlerFn` http.HandlerFunc.
+func (mx *Mux) Post(pattern string, handlerFn http.HandlerFunc) {
+ mx.handle(mPOST, pattern, handlerFn)
+}
+
+// Put adds the route `pattern` that matches a PUT http method to
+// execute the `handlerFn` http.HandlerFunc.
+func (mx *Mux) Put(pattern string, handlerFn http.HandlerFunc) {
+ mx.handle(mPUT, pattern, handlerFn)
+}
+
+// Trace adds the route `pattern` that matches a TRACE http method to
+// execute the `handlerFn` http.HandlerFunc.
+func (mx *Mux) Trace(pattern string, handlerFn http.HandlerFunc) {
+ mx.handle(mTRACE, pattern, handlerFn)
+}
+
+// NotFound sets a custom http.HandlerFunc for routing paths that could
+// not be found. The default 404 handler is `http.NotFound`.
+func (mx *Mux) NotFound(handlerFn http.HandlerFunc) {
+ // Build NotFound handler chain
+ m := mx
+ hFn := handlerFn
+ if mx.inline && mx.parent != nil {
+ m = mx.parent
+ hFn = Chain(mx.middlewares...).HandlerFunc(hFn).ServeHTTP
+ }
+
+ // Update the notFoundHandler from this point forward
+ m.notFoundHandler = hFn
+ m.updateSubRoutes(func(subMux *Mux) {
+ if subMux.notFoundHandler == nil {
+ subMux.NotFound(hFn)
+ }
+ })
+}
+
+// MethodNotAllowed sets a custom http.HandlerFunc for routing paths where the
+// method is unresolved. The default handler returns a 405 with an empty body.
+func (mx *Mux) MethodNotAllowed(handlerFn http.HandlerFunc) {
+ // Build MethodNotAllowed handler chain
+ m := mx
+ hFn := handlerFn
+ if mx.inline && mx.parent != nil {
+ m = mx.parent
+ hFn = Chain(mx.middlewares...).HandlerFunc(hFn).ServeHTTP
+ }
+
+ // Update the methodNotAllowedHandler from this point forward
+ m.methodNotAllowedHandler = hFn
+ m.updateSubRoutes(func(subMux *Mux) {
+ if subMux.methodNotAllowedHandler == nil {
+ subMux.MethodNotAllowed(hFn)
+ }
+ })
+}
+
+// With adds inline middlewares for an endpoint handler.
+func (mx *Mux) With(middlewares ...func(http.Handler) http.Handler) Router {
+ // Similarly as in handle(), we must build the mux handler once further
+ // middleware registration isn't allowed for this stack, like now.
+ if !mx.inline && mx.handler == nil {
+ mx.buildRouteHandler()
+ }
+
+ // Copy middlewares from parent inline muxs
+ var mws Middlewares
+ if mx.inline {
+ mws = make(Middlewares, len(mx.middlewares))
+ copy(mws, mx.middlewares)
+ }
+ mws = append(mws, middlewares...)
+
+ im := &Mux{pool: mx.pool, inline: true, parent: mx, tree: mx.tree, middlewares: mws}
+
+ return im
+}
+
+// Group creates a new inline-Mux with a fresh middleware stack. It's useful
+// for a group of handlers along the same routing path that use an additional
+// set of middlewares. See _examples/.
+func (mx *Mux) Group(fn func(r Router)) Router {
+ im := mx.With().(*Mux)
+ if fn != nil {
+ fn(im)
+ }
+ return im
+}
+
+// Route creates a new Mux with a fresh middleware stack and mounts it
+// along the `pattern` as a subrouter. Effectively, this is a short-hand
+// call to Mount. See _examples/.
+func (mx *Mux) Route(pattern string, fn func(r Router)) Router {
+ subRouter := NewRouter()
+ if fn != nil {
+ fn(subRouter)
+ }
+ mx.Mount(pattern, subRouter)
+ return subRouter
+}
+
+// Mount attaches another http.Handler or chi Router as a subrouter along a routing
+// path. It's very useful to split up a large API as many independent routers and
+// compose them as a single service using Mount. See _examples/.
+//
+// Note that Mount() simply sets a wildcard along the `pattern` that will continue
+// routing at the `handler`, which in most cases is another chi.Router. As a result,
+// if you define two Mount() routes on the exact same pattern the mount will panic.
+func (mx *Mux) Mount(pattern string, handler http.Handler) {
+ // Provide runtime safety for ensuring a pattern isn't mounted on an existing
+ // routing pattern.
+ if mx.tree.findPattern(pattern+"*") || mx.tree.findPattern(pattern+"/*") {
+ panic(fmt.Sprintf("chi: attempting to Mount() a handler on an existing path, '%s'", pattern))
+ }
+
+ // Assign sub-Router's with the parent not found & method not allowed handler if not specified.
+ subr, ok := handler.(*Mux)
+ if ok && subr.notFoundHandler == nil && mx.notFoundHandler != nil {
+ subr.NotFound(mx.notFoundHandler)
+ }
+ if ok && subr.methodNotAllowedHandler == nil && mx.methodNotAllowedHandler != nil {
+ subr.MethodNotAllowed(mx.methodNotAllowedHandler)
+ }
+
+ // Wrap the sub-router in a handlerFunc to scope the request path for routing.
+ mountHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ rctx := RouteContext(r.Context())
+ rctx.RoutePath = mx.nextRoutePath(rctx)
+ handler.ServeHTTP(w, r)
+ })
+
+ if pattern == "" || pattern[len(pattern)-1] != '/' {
+ mx.handle(mALL|mSTUB, pattern, mountHandler)
+ mx.handle(mALL|mSTUB, pattern+"/", mountHandler)
+ pattern += "/"
+ }
+
+ method := mALL
+ subroutes, _ := handler.(Routes)
+ if subroutes != nil {
+ method |= mSTUB
+ }
+ n := mx.handle(method, pattern+"*", mountHandler)
+
+ if subroutes != nil {
+ n.subroutes = subroutes
+ }
+}
+
+// Routes returns a slice of routing information from the tree,
+// useful for traversing available routes of a router.
+func (mx *Mux) Routes() []Route {
+ return mx.tree.routes()
+}
+
+// Middlewares returns a slice of middleware handler functions.
+func (mx *Mux) Middlewares() Middlewares {
+ return mx.middlewares
+}
+
+// Match searches the routing tree for a handler that matches the method/path.
+// It's similar to routing a http request, but without executing the handler
+// thereafter.
+//
+// Note: the *Context state is updated during execution, so manage
+// the state carefully or make a NewRouteContext().
+func (mx *Mux) Match(rctx *Context, method, path string) bool {
+ m, ok := methodMap[method]
+ if !ok {
+ return false
+ }
+
+ node, _, h := mx.tree.FindRoute(rctx, m, path)
+
+ if node != nil && node.subroutes != nil {
+ rctx.RoutePath = mx.nextRoutePath(rctx)
+ return node.subroutes.Match(rctx, method, rctx.RoutePath)
+ }
+
+ return h != nil
+}
+
+// NotFoundHandler returns the default Mux 404 responder whenever a route
+// cannot be found.
+func (mx *Mux) NotFoundHandler() http.HandlerFunc {
+ if mx.notFoundHandler != nil {
+ return mx.notFoundHandler
+ }
+ return http.NotFound
+}
+
+// MethodNotAllowedHandler returns the default Mux 405 responder whenever
+// a method cannot be resolved for a route.
+func (mx *Mux) MethodNotAllowedHandler() http.HandlerFunc {
+ if mx.methodNotAllowedHandler != nil {
+ return mx.methodNotAllowedHandler
+ }
+ return methodNotAllowedHandler
+}
+
+// buildRouteHandler builds the single mux handler that is a chain of the middleware
+// stack, as defined by calls to Use(), and the tree router (Mux) itself. After this
+// point, no other middlewares can be registered on this Mux's stack. But you can still
+// compose additional middlewares via Group()'s or using a chained middleware handler.
+func (mx *Mux) buildRouteHandler() {
+ mx.handler = chain(mx.middlewares, http.HandlerFunc(mx.routeHTTP))
+}
+
+// handle registers a http.Handler in the routing tree for a particular http method
+// and routing pattern.
+func (mx *Mux) handle(method methodTyp, pattern string, handler http.Handler) *node {
+ if len(pattern) == 0 || pattern[0] != '/' {
+ panic(fmt.Sprintf("chi: routing pattern must begin with '/' in '%s'", pattern))
+ }
+
+ // Build the final routing handler for this Mux.
+ if !mx.inline && mx.handler == nil {
+ mx.buildRouteHandler()
+ }
+
+ // Build endpoint handler with inline middlewares for the route
+ var h http.Handler
+ if mx.inline {
+ mx.handler = http.HandlerFunc(mx.routeHTTP)
+ h = Chain(mx.middlewares...).Handler(handler)
+ } else {
+ h = handler
+ }
+
+ // Add the endpoint to the tree and return the node
+ return mx.tree.InsertRoute(method, pattern, h)
+}
+
+// routeHTTP routes a http.Request through the Mux routing tree to serve
+// the matching handler for a particular http method.
+func (mx *Mux) routeHTTP(w http.ResponseWriter, r *http.Request) {
+ // Grab the route context object
+ rctx := r.Context().Value(RouteCtxKey).(*Context)
+
+ // The request routing path
+ routePath := rctx.RoutePath
+ if routePath == "" {
+ if r.URL.RawPath != "" {
+ routePath = r.URL.RawPath
+ } else {
+ routePath = r.URL.Path
+ }
+ }
+
+ // Check if method is supported by chi
+ if rctx.RouteMethod == "" {
+ rctx.RouteMethod = r.Method
+ }
+ method, ok := methodMap[rctx.RouteMethod]
+ if !ok {
+ mx.MethodNotAllowedHandler().ServeHTTP(w, r)
+ return
+ }
+
+ // Find the route
+ if _, _, h := mx.tree.FindRoute(rctx, method, routePath); h != nil {
+ h.ServeHTTP(w, r)
+ return
+ }
+ if rctx.methodNotAllowed {
+ mx.MethodNotAllowedHandler().ServeHTTP(w, r)
+ } else {
+ mx.NotFoundHandler().ServeHTTP(w, r)
+ }
+}
+
+func (mx *Mux) nextRoutePath(rctx *Context) string {
+ routePath := "/"
+ nx := len(rctx.routeParams.Keys) - 1 // index of last param in list
+ if nx >= 0 && rctx.routeParams.Keys[nx] == "*" && len(rctx.routeParams.Values) > nx {
+ routePath += rctx.routeParams.Values[nx]
+ }
+ return routePath
+}
+
+// Recursively update data on child routers.
+func (mx *Mux) updateSubRoutes(fn func(subMux *Mux)) {
+ for _, r := range mx.tree.routes() {
+ subMux, ok := r.SubRoutes.(*Mux)
+ if !ok {
+ continue
+ }
+ fn(subMux)
+ }
+}
+
+// methodNotAllowedHandler is a helper function to respond with a 405,
+// method not allowed.
+func methodNotAllowedHandler(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(405)
+ w.Write(nil)
+}
diff --git a/vendor/github.com/go-chi/chi/tree.go b/vendor/github.com/go-chi/chi/tree.go
new file mode 100644
index 0000000..8a044f3
--- /dev/null
+++ b/vendor/github.com/go-chi/chi/tree.go
@@ -0,0 +1,846 @@
+package chi
+
+// Radix tree implementation below is a based on the original work by
+// Armon Dadgar in https://github.com/armon/go-radix/blob/master/radix.go
+// (MIT licensed). It's been heavily modified for use as a HTTP routing tree.
+
+import (
+ "fmt"
+ "math"
+ "net/http"
+ "regexp"
+ "sort"
+ "strconv"
+ "strings"
+)
+
+type methodTyp int
+
+const (
+ mSTUB methodTyp = 1 << iota
+ mCONNECT
+ mDELETE
+ mGET
+ mHEAD
+ mOPTIONS
+ mPATCH
+ mPOST
+ mPUT
+ mTRACE
+)
+
+var mALL = mCONNECT | mDELETE | mGET | mHEAD |
+ mOPTIONS | mPATCH | mPOST | mPUT | mTRACE
+
+var methodMap = map[string]methodTyp{
+ http.MethodConnect: mCONNECT,
+ http.MethodDelete: mDELETE,
+ http.MethodGet: mGET,
+ http.MethodHead: mHEAD,
+ http.MethodOptions: mOPTIONS,
+ http.MethodPatch: mPATCH,
+ http.MethodPost: mPOST,
+ http.MethodPut: mPUT,
+ http.MethodTrace: mTRACE,
+}
+
+// RegisterMethod adds support for custom HTTP method handlers, available
+// via Router#Method and Router#MethodFunc
+func RegisterMethod(method string) {
+ if method == "" {
+ return
+ }
+ method = strings.ToUpper(method)
+ if _, ok := methodMap[method]; ok {
+ return
+ }
+ n := len(methodMap)
+ if n > strconv.IntSize {
+ panic(fmt.Sprintf("chi: max number of methods reached (%d)", strconv.IntSize))
+ }
+ mt := methodTyp(math.Exp2(float64(n)))
+ methodMap[method] = mt
+ mALL |= mt
+}
+
+type nodeTyp uint8
+
+const (
+ ntStatic nodeTyp = iota // /home
+ ntRegexp // /{id:[0-9]+}
+ ntParam // /{user}
+ ntCatchAll // /api/v1/*
+)
+
+type node struct {
+ // node type: static, regexp, param, catchAll
+ typ nodeTyp
+
+ // first byte of the prefix
+ label byte
+
+ // first byte of the child prefix
+ tail byte
+
+ // prefix is the common prefix we ignore
+ prefix string
+
+ // regexp matcher for regexp nodes
+ rex *regexp.Regexp
+
+ // HTTP handler endpoints on the leaf node
+ endpoints endpoints
+
+ // subroutes on the leaf node
+ subroutes Routes
+
+ // child nodes should be stored in-order for iteration,
+ // in groups of the node type.
+ children [ntCatchAll + 1]nodes
+}
+
+// endpoints is a mapping of http method constants to handlers
+// for a given route.
+type endpoints map[methodTyp]*endpoint
+
+type endpoint struct {
+ // endpoint handler
+ handler http.Handler
+
+ // pattern is the routing pattern for handler nodes
+ pattern string
+
+ // parameter keys recorded on handler nodes
+ paramKeys []string
+}
+
+func (s endpoints) Value(method methodTyp) *endpoint {
+ mh, ok := s[method]
+ if !ok {
+ mh = &endpoint{}
+ s[method] = mh
+ }
+ return mh
+}
+
+func (n *node) InsertRoute(method methodTyp, pattern string, handler http.Handler) *node {
+ var parent *node
+ search := pattern
+
+ for {
+ // Handle key exhaustion
+ if len(search) == 0 {
+ // Insert or update the node's leaf handler
+ n.setEndpoint(method, handler, pattern)
+ return n
+ }
+
+ // We're going to be searching for a wild node next,
+ // in this case, we need to get the tail
+ var label = search[0]
+ var segTail byte
+ var segEndIdx int
+ var segTyp nodeTyp
+ var segRexpat string
+ if label == '{' || label == '*' {
+ segTyp, _, segRexpat, segTail, _, segEndIdx = patNextSegment(search)
+ }
+
+ var prefix string
+ if segTyp == ntRegexp {
+ prefix = segRexpat
+ }
+
+ // Look for the edge to attach to
+ parent = n
+ n = n.getEdge(segTyp, label, segTail, prefix)
+
+ // No edge, create one
+ if n == nil {
+ child := &node{label: label, tail: segTail, prefix: search}
+ hn := parent.addChild(child, search)
+ hn.setEndpoint(method, handler, pattern)
+
+ return hn
+ }
+
+ // Found an edge to match the pattern
+
+ if n.typ > ntStatic {
+ // We found a param node, trim the param from the search path and continue.
+ // This param/wild pattern segment would already be on the tree from a previous
+ // call to addChild when creating a new node.
+ search = search[segEndIdx:]
+ continue
+ }
+
+ // Static nodes fall below here.
+ // Determine longest prefix of the search key on match.
+ commonPrefix := longestPrefix(search, n.prefix)
+ if commonPrefix == len(n.prefix) {
+ // the common prefix is as long as the current node's prefix we're attempting to insert.
+ // keep the search going.
+ search = search[commonPrefix:]
+ continue
+ }
+
+ // Split the node
+ child := &node{
+ typ: ntStatic,
+ prefix: search[:commonPrefix],
+ }
+ parent.replaceChild(search[0], segTail, child)
+
+ // Restore the existing node
+ n.label = n.prefix[commonPrefix]
+ n.prefix = n.prefix[commonPrefix:]
+ child.addChild(n, n.prefix)
+
+ // If the new key is a subset, set the method/handler on this node and finish.
+ search = search[commonPrefix:]
+ if len(search) == 0 {
+ child.setEndpoint(method, handler, pattern)
+ return child
+ }
+
+ // Create a new edge for the node
+ subchild := &node{
+ typ: ntStatic,
+ label: search[0],
+ prefix: search,
+ }
+ hn := child.addChild(subchild, search)
+ hn.setEndpoint(method, handler, pattern)
+ return hn
+ }
+}
+
+// addChild appends the new `child` node to the tree using the `pattern` as the trie key.
+// For a URL router like chi's, we split the static, param, regexp and wildcard segments
+// into different nodes. In addition, addChild will recursively call itself until every
+// pattern segment is added to the url pattern tree as individual nodes, depending on type.
+func (n *node) addChild(child *node, prefix string) *node {
+ search := prefix
+
+ // handler leaf node added to the tree is the child.
+ // this may be overridden later down the flow
+ hn := child
+
+ // Parse next segment
+ segTyp, _, segRexpat, segTail, segStartIdx, segEndIdx := patNextSegment(search)
+
+ // Add child depending on next up segment
+ switch segTyp {
+
+ case ntStatic:
+ // Search prefix is all static (that is, has no params in path)
+ // noop
+
+ default:
+ // Search prefix contains a param, regexp or wildcard
+
+ if segTyp == ntRegexp {
+ rex, err := regexp.Compile(segRexpat)
+ if err != nil {
+ panic(fmt.Sprintf("chi: invalid regexp pattern '%s' in route param", segRexpat))
+ }
+ child.prefix = segRexpat
+ child.rex = rex
+ }
+
+ if segStartIdx == 0 {
+ // Route starts with a param
+ child.typ = segTyp
+
+ if segTyp == ntCatchAll {
+ segStartIdx = -1
+ } else {
+ segStartIdx = segEndIdx
+ }
+ if segStartIdx < 0 {
+ segStartIdx = len(search)
+ }
+ child.tail = segTail // for params, we set the tail
+
+ if segStartIdx != len(search) {
+ // add static edge for the remaining part, split the end.
+ // its not possible to have adjacent param nodes, so its certainly
+ // going to be a static node next.
+
+ search = search[segStartIdx:] // advance search position
+
+ nn := &node{
+ typ: ntStatic,
+ label: search[0],
+ prefix: search,
+ }
+ hn = child.addChild(nn, search)
+ }
+
+ } else if segStartIdx > 0 {
+ // Route has some param
+
+ // starts with a static segment
+ child.typ = ntStatic
+ child.prefix = search[:segStartIdx]
+ child.rex = nil
+
+ // add the param edge node
+ search = search[segStartIdx:]
+
+ nn := &node{
+ typ: segTyp,
+ label: search[0],
+ tail: segTail,
+ }
+ hn = child.addChild(nn, search)
+
+ }
+ }
+
+ n.children[child.typ] = append(n.children[child.typ], child)
+ n.children[child.typ].Sort()
+ return hn
+}
+
+func (n *node) replaceChild(label, tail byte, child *node) {
+ for i := 0; i < len(n.children[child.typ]); i++ {
+ if n.children[child.typ][i].label == label && n.children[child.typ][i].tail == tail {
+ n.children[child.typ][i] = child
+ n.children[child.typ][i].label = label
+ n.children[child.typ][i].tail = tail
+ return
+ }
+ }
+ panic("chi: replacing missing child")
+}
+
+func (n *node) getEdge(ntyp nodeTyp, label, tail byte, prefix string) *node {
+ nds := n.children[ntyp]
+ for i := 0; i < len(nds); i++ {
+ if nds[i].label == label && nds[i].tail == tail {
+ if ntyp == ntRegexp && nds[i].prefix != prefix {
+ continue
+ }
+ return nds[i]
+ }
+ }
+ return nil
+}
+
+func (n *node) setEndpoint(method methodTyp, handler http.Handler, pattern string) {
+ // Set the handler for the method type on the node
+ if n.endpoints == nil {
+ n.endpoints = make(endpoints, 0)
+ }
+
+ paramKeys := patParamKeys(pattern)
+
+ if method&mSTUB == mSTUB {
+ n.endpoints.Value(mSTUB).handler = handler
+ }
+ if method&mALL == mALL {
+ h := n.endpoints.Value(mALL)
+ h.handler = handler
+ h.pattern = pattern
+ h.paramKeys = paramKeys
+ for _, m := range methodMap {
+ h := n.endpoints.Value(m)
+ h.handler = handler
+ h.pattern = pattern
+ h.paramKeys = paramKeys
+ }
+ } else {
+ h := n.endpoints.Value(method)
+ h.handler = handler
+ h.pattern = pattern
+ h.paramKeys = paramKeys
+ }
+}
+
+func (n *node) FindRoute(rctx *Context, method methodTyp, path string) (*node, endpoints, http.Handler) {
+ // Reset the context routing pattern and params
+ rctx.routePattern = ""
+ rctx.routeParams.Keys = rctx.routeParams.Keys[:0]
+ rctx.routeParams.Values = rctx.routeParams.Values[:0]
+
+ // Find the routing handlers for the path
+ rn := n.findRoute(rctx, method, path)
+ if rn == nil {
+ return nil, nil, nil
+ }
+
+ // Record the routing params in the request lifecycle
+ rctx.URLParams.Keys = append(rctx.URLParams.Keys, rctx.routeParams.Keys...)
+ rctx.URLParams.Values = append(rctx.URLParams.Values, rctx.routeParams.Values...)
+
+ // Record the routing pattern in the request lifecycle
+ if rn.endpoints[method].pattern != "" {
+ rctx.routePattern = rn.endpoints[method].pattern
+ rctx.RoutePatterns = append(rctx.RoutePatterns, rctx.routePattern)
+ }
+
+ return rn, rn.endpoints, rn.endpoints[method].handler
+}
+
+// Recursive edge traversal by checking all nodeTyp groups along the way.
+// It's like searching through a multi-dimensional radix trie.
+func (n *node) findRoute(rctx *Context, method methodTyp, path string) *node {
+ nn := n
+ search := path
+
+ for t, nds := range nn.children {
+ ntyp := nodeTyp(t)
+ if len(nds) == 0 {
+ continue
+ }
+
+ var xn *node
+ xsearch := search
+
+ var label byte
+ if search != "" {
+ label = search[0]
+ }
+
+ switch ntyp {
+ case ntStatic:
+ xn = nds.findEdge(label)
+ if xn == nil || !strings.HasPrefix(xsearch, xn.prefix) {
+ continue
+ }
+ xsearch = xsearch[len(xn.prefix):]
+
+ case ntParam, ntRegexp:
+ // short-circuit and return no matching route for empty param values
+ if xsearch == "" {
+ continue
+ }
+
+ // serially loop through each node grouped by the tail delimiter
+ for idx := 0; idx < len(nds); idx++ {
+ xn = nds[idx]
+
+ // label for param nodes is the delimiter byte
+ p := strings.IndexByte(xsearch, xn.tail)
+
+ if p < 0 {
+ if xn.tail == '/' {
+ p = len(xsearch)
+ } else {
+ continue
+ }
+ }
+
+ if ntyp == ntRegexp && xn.rex != nil {
+ if xn.rex.Match([]byte(xsearch[:p])) == false {
+ continue
+ }
+ } else if strings.IndexByte(xsearch[:p], '/') != -1 {
+ // avoid a match across path segments
+ continue
+ }
+
+ rctx.routeParams.Values = append(rctx.routeParams.Values, xsearch[:p])
+ xsearch = xsearch[p:]
+ break
+ }
+
+ default:
+ // catch-all nodes
+ rctx.routeParams.Values = append(rctx.routeParams.Values, search)
+ xn = nds[0]
+ xsearch = ""
+ }
+
+ if xn == nil {
+ continue
+ }
+
+ // did we find it yet?
+ if len(xsearch) == 0 {
+ if xn.isLeaf() {
+ h, _ := xn.endpoints[method]
+ if h != nil && h.handler != nil {
+ rctx.routeParams.Keys = append(rctx.routeParams.Keys, h.paramKeys...)
+ return xn
+ }
+
+ // flag that the routing context found a route, but not a corresponding
+ // supported method
+ rctx.methodNotAllowed = true
+ }
+ }
+
+ // recursively find the next node..
+ fin := xn.findRoute(rctx, method, xsearch)
+ if fin != nil {
+ return fin
+ }
+
+ // Did not find final handler, let's remove the param here if it was set
+ if xn.typ > ntStatic {
+ if len(rctx.routeParams.Values) > 0 {
+ rctx.routeParams.Values = rctx.routeParams.Values[:len(rctx.routeParams.Values)-1]
+ }
+ }
+
+ }
+
+ return nil
+}
+
+func (n *node) findEdge(ntyp nodeTyp, label byte) *node {
+ nds := n.children[ntyp]
+ num := len(nds)
+ idx := 0
+
+ switch ntyp {
+ case ntStatic, ntParam, ntRegexp:
+ i, j := 0, num-1
+ for i <= j {
+ idx = i + (j-i)/2
+ if label > nds[idx].label {
+ i = idx + 1
+ } else if label < nds[idx].label {
+ j = idx - 1
+ } else {
+ i = num // breaks cond
+ }
+ }
+ if nds[idx].label != label {
+ return nil
+ }
+ return nds[idx]
+
+ default: // catch all
+ return nds[idx]
+ }
+}
+
+func (n *node) isEmpty() bool {
+ for _, nds := range n.children {
+ if len(nds) > 0 {
+ return false
+ }
+ }
+ return true
+}
+
+func (n *node) isLeaf() bool {
+ return n.endpoints != nil
+}
+
+func (n *node) findPattern(pattern string) bool {
+ nn := n
+ for _, nds := range nn.children {
+ if len(nds) == 0 {
+ continue
+ }
+
+ n = nn.findEdge(nds[0].typ, pattern[0])
+ if n == nil {
+ continue
+ }
+
+ var idx int
+ var xpattern string
+
+ switch n.typ {
+ case ntStatic:
+ idx = longestPrefix(pattern, n.prefix)
+ if idx < len(n.prefix) {
+ continue
+ }
+
+ case ntParam, ntRegexp:
+ idx = strings.IndexByte(pattern, '}') + 1
+
+ case ntCatchAll:
+ idx = longestPrefix(pattern, "*")
+
+ default:
+ panic("chi: unknown node type")
+ }
+
+ xpattern = pattern[idx:]
+ if len(xpattern) == 0 {
+ return true
+ }
+
+ return n.findPattern(xpattern)
+ }
+ return false
+}
+
+func (n *node) routes() []Route {
+ rts := []Route{}
+
+ n.walk(func(eps endpoints, subroutes Routes) bool {
+ if eps[mSTUB] != nil && eps[mSTUB].handler != nil && subroutes == nil {
+ return false
+ }
+
+ // Group methodHandlers by unique patterns
+ pats := make(map[string]endpoints, 0)
+
+ for mt, h := range eps {
+ if h.pattern == "" {
+ continue
+ }
+ p, ok := pats[h.pattern]
+ if !ok {
+ p = endpoints{}
+ pats[h.pattern] = p
+ }
+ p[mt] = h
+ }
+
+ for p, mh := range pats {
+ hs := make(map[string]http.Handler, 0)
+ if mh[mALL] != nil && mh[mALL].handler != nil {
+ hs["*"] = mh[mALL].handler
+ }
+
+ for mt, h := range mh {
+ if h.handler == nil {
+ continue
+ }
+ m := methodTypString(mt)
+ if m == "" {
+ continue
+ }
+ hs[m] = h.handler
+ }
+
+ rt := Route{p, hs, subroutes}
+ rts = append(rts, rt)
+ }
+
+ return false
+ })
+
+ return rts
+}
+
+func (n *node) walk(fn func(eps endpoints, subroutes Routes) bool) bool {
+ // Visit the leaf values if any
+ if (n.endpoints != nil || n.subroutes != nil) && fn(n.endpoints, n.subroutes) {
+ return true
+ }
+
+ // Recurse on the children
+ for _, ns := range n.children {
+ for _, cn := range ns {
+ if cn.walk(fn) {
+ return true
+ }
+ }
+ }
+ return false
+}
+
+// patNextSegment returns the next segment details from a pattern:
+// node type, param key, regexp string, param tail byte, param starting index, param ending index
+func patNextSegment(pattern string) (nodeTyp, string, string, byte, int, int) {
+ ps := strings.Index(pattern, "{")
+ ws := strings.Index(pattern, "*")
+
+ if ps < 0 && ws < 0 {
+ return ntStatic, "", "", 0, 0, len(pattern) // we return the entire thing
+ }
+
+ // Sanity check
+ if ps >= 0 && ws >= 0 && ws < ps {
+ panic("chi: wildcard '*' must be the last pattern in a route, otherwise use a '{param}'")
+ }
+
+ var tail byte = '/' // Default endpoint tail to / byte
+
+ if ps >= 0 {
+ // Param/Regexp pattern is next
+ nt := ntParam
+
+ // Read to closing } taking into account opens and closes in curl count (cc)
+ cc := 0
+ pe := ps
+ for i, c := range pattern[ps:] {
+ if c == '{' {
+ cc++
+ } else if c == '}' {
+ cc--
+ if cc == 0 {
+ pe = ps + i
+ break
+ }
+ }
+ }
+ if pe == ps {
+ panic("chi: route param closing delimiter '}' is missing")
+ }
+
+ key := pattern[ps+1 : pe]
+ pe++ // set end to next position
+
+ if pe < len(pattern) {
+ tail = pattern[pe]
+ }
+
+ var rexpat string
+ if idx := strings.Index(key, ":"); idx >= 0 {
+ nt = ntRegexp
+ rexpat = key[idx+1:]
+ key = key[:idx]
+ }
+
+ if len(rexpat) > 0 {
+ if rexpat[0] != '^' {
+ rexpat = "^" + rexpat
+ }
+ if rexpat[len(rexpat)-1] != '$' {
+ rexpat = rexpat + "$"
+ }
+ }
+
+ return nt, key, rexpat, tail, ps, pe
+ }
+
+ // Wildcard pattern as finale
+ if ws < len(pattern)-1 {
+ panic("chi: wildcard '*' must be the last value in a route. trim trailing text or use a '{param}' instead")
+ }
+ return ntCatchAll, "*", "", 0, ws, len(pattern)
+}
+
+func patParamKeys(pattern string) []string {
+ pat := pattern
+ paramKeys := []string{}
+ for {
+ ptyp, paramKey, _, _, _, e := patNextSegment(pat)
+ if ptyp == ntStatic {
+ return paramKeys
+ }
+ for i := 0; i < len(paramKeys); i++ {
+ if paramKeys[i] == paramKey {
+ panic(fmt.Sprintf("chi: routing pattern '%s' contains duplicate param key, '%s'", pattern, paramKey))
+ }
+ }
+ paramKeys = append(paramKeys, paramKey)
+ pat = pat[e:]
+ }
+}
+
+// longestPrefix finds the length of the shared prefix
+// of two strings
+func longestPrefix(k1, k2 string) int {
+ max := len(k1)
+ if l := len(k2); l < max {
+ max = l
+ }
+ var i int
+ for i = 0; i < max; i++ {
+ if k1[i] != k2[i] {
+ break
+ }
+ }
+ return i
+}
+
+func methodTypString(method methodTyp) string {
+ for s, t := range methodMap {
+ if method == t {
+ return s
+ }
+ }
+ return ""
+}
+
+type nodes []*node
+
+// Sort the list of nodes by label
+func (ns nodes) Sort() { sort.Sort(ns); ns.tailSort() }
+func (ns nodes) Len() int { return len(ns) }
+func (ns nodes) Swap(i, j int) { ns[i], ns[j] = ns[j], ns[i] }
+func (ns nodes) Less(i, j int) bool { return ns[i].label < ns[j].label }
+
+// tailSort pushes nodes with '/' as the tail to the end of the list for param nodes.
+// The list order determines the traversal order.
+func (ns nodes) tailSort() {
+ for i := len(ns) - 1; i >= 0; i-- {
+ if ns[i].typ > ntStatic && ns[i].tail == '/' {
+ ns.Swap(i, len(ns)-1)
+ return
+ }
+ }
+}
+
+func (ns nodes) findEdge(label byte) *node {
+ num := len(ns)
+ idx := 0
+ i, j := 0, num-1
+ for i <= j {
+ idx = i + (j-i)/2
+ if label > ns[idx].label {
+ i = idx + 1
+ } else if label < ns[idx].label {
+ j = idx - 1
+ } else {
+ i = num // breaks cond
+ }
+ }
+ if ns[idx].label != label {
+ return nil
+ }
+ return ns[idx]
+}
+
+// Route describes the details of a routing handler.
+type Route struct {
+ Pattern string
+ Handlers map[string]http.Handler
+ SubRoutes Routes
+}
+
+// WalkFunc is the type of the function called for each method and route visited by Walk.
+type WalkFunc func(method string, route string, handler http.Handler, middlewares ...func(http.Handler) http.Handler) error
+
+// Walk walks any router tree that implements Routes interface.
+func Walk(r Routes, walkFn WalkFunc) error {
+ return walk(r, walkFn, "")
+}
+
+func walk(r Routes, walkFn WalkFunc, parentRoute string, parentMw ...func(http.Handler) http.Handler) error {
+ for _, route := range r.Routes() {
+ mws := make([]func(http.Handler) http.Handler, len(parentMw))
+ copy(mws, parentMw)
+ mws = append(mws, r.Middlewares()...)
+
+ if route.SubRoutes != nil {
+ if err := walk(route.SubRoutes, walkFn, parentRoute+route.Pattern, mws...); err != nil {
+ return err
+ }
+ continue
+ }
+
+ for method, handler := range route.Handlers {
+ if method == "*" {
+ // Ignore a "catchAll" method, since we pass down all the specific methods for each route.
+ continue
+ }
+
+ fullRoute := parentRoute + route.Pattern
+
+ if chain, ok := handler.(*ChainHandler); ok {
+ if err := walkFn(method, fullRoute, chain.Endpoint, append(mws, chain.Middlewares...)...); err != nil {
+ return err
+ }
+ } else {
+ if err := walkFn(method, fullRoute, handler, mws...); err != nil {
+ return err
+ }
+ }
+ }
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/gofrs/uuid/.gitignore b/vendor/github.com/gofrs/uuid/.gitignore
new file mode 100644
index 0000000..666dbbb
--- /dev/null
+++ b/vendor/github.com/gofrs/uuid/.gitignore
@@ -0,0 +1,15 @@
+# Binaries for programs and plugins
+*.exe
+*.exe~
+*.dll
+*.so
+*.dylib
+
+# Test binary, build with `go test -c`
+*.test
+
+# Output of the go coverage tool, specifically when used with LiteIDE
+*.out
+
+# binary bundle generated by go-fuzz
+uuid-fuzz.zip
diff --git a/vendor/github.com/gofrs/uuid/.travis.yml b/vendor/github.com/gofrs/uuid/.travis.yml
new file mode 100644
index 0000000..ee1e4fa
--- /dev/null
+++ b/vendor/github.com/gofrs/uuid/.travis.yml
@@ -0,0 +1,23 @@
+language: go
+sudo: false
+go:
+ - 1.7.x
+ - 1.8.x
+ - 1.9.x
+ - 1.10.x
+ - 1.11.x
+ - tip
+matrix:
+ allow_failures:
+ - go: tip
+ fast_finish: true
+env:
+ - GO111MODULE=on
+before_install:
+ - go get golang.org/x/tools/cmd/cover
+script:
+ - go test ./... -race -coverprofile=coverage.txt -covermode=atomic
+after_success:
+ - bash <(curl -s https://codecov.io/bash)
+notifications:
+ email: false
diff --git a/vendor/github.com/satori/go.uuid/LICENSE b/vendor/github.com/gofrs/uuid/LICENSE
similarity index 94%
rename from vendor/github.com/satori/go.uuid/LICENSE
rename to vendor/github.com/gofrs/uuid/LICENSE
index 488357b..926d549 100644
--- a/vendor/github.com/satori/go.uuid/LICENSE
+++ b/vendor/github.com/gofrs/uuid/LICENSE
@@ -1,4 +1,4 @@
-Copyright (C) 2013-2016 by Maxim Bublis
+Copyright (C) 2013-2018 by Maxim Bublis
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
diff --git a/vendor/github.com/gofrs/uuid/README.md b/vendor/github.com/gofrs/uuid/README.md
new file mode 100644
index 0000000..efc3204
--- /dev/null
+++ b/vendor/github.com/gofrs/uuid/README.md
@@ -0,0 +1,109 @@
+# UUID
+
+[](https://github.com/gofrs/uuid/blob/master/LICENSE)
+[](https://travis-ci.org/gofrs/uuid)
+[](http://godoc.org/github.com/gofrs/uuid)
+[](https://codecov.io/gh/gofrs/uuid/)
+[](https://goreportcard.com/report/github.com/gofrs/uuid)
+
+Package uuid provides a pure Go implementation of Universally Unique Identifiers
+(UUID) variant as defined in RFC-4122. This package supports both the creation
+and parsing of UUIDs in different formats.
+
+This package supports the following UUID versions:
+* Version 1, based on timestamp and MAC address (RFC-4122)
+* Version 2, based on timestamp, MAC address and POSIX UID/GID (DCE 1.1)
+* Version 3, based on MD5 hashing of a named value (RFC-4122)
+* Version 4, based on random numbers (RFC-4122)
+* Version 5, based on SHA-1 hashing of a named value (RFC-4122)
+
+## Project History
+
+This project was originally forked from the
+[github.com/satori/go.uuid](https://github.com/satori/go.uuid) repository after
+it appeared to be no longer maintained, while exhibiting [critical
+flaws](https://github.com/satori/go.uuid/issues/73). We have decided to take
+over this project to ensure it receives regular maintenance for the benefit of
+the larger Go community.
+
+We'd like to thank Maxim Bublis for his hard work on the original iteration of
+the package.
+
+## License
+
+This source code of this package is released under the MIT License. Please see
+the [LICENSE](https://github.com/gofrs/uuid/blob/master/LICENSE) for the full
+content of the license.
+
+## Recommended Package Version
+
+We recommend using v2.0.0+ of this package, as versions prior to 2.0.0 were
+created before our fork of the original package and have some known
+deficiencies.
+
+## Installation
+
+It is recommended to use a package manager like `dep` that understands tagged
+releases of a package, as well as semantic versioning.
+
+If you are unable to make use of a dependency manager with your project, you can
+use the `go get` command to download it directly:
+
+```Shell
+$ go get github.com/gofrs/uuid
+```
+
+## Requirements
+
+Due to subtests not being supported in older versions of Go, this package is
+only regularly tested against Go 1.7+. This package may work perfectly fine with
+Go 1.2+, but support for these older versions is not actively maintained.
+
+## Go 1.11 Modules
+
+As of v3.2.0, this repository no longer adopts Go modules, and v3.2.0 no longer has a `go.mod` file. As a result, v3.2.0 also drops support for the `github.com/gofrs/uuid/v3` import path. Only module-based consumers are impacted. With the v3.2.0 release, _all_ gofrs/uuid consumers should use the `github.com/gofrs/uuid` import path.
+
+An existing module-based consumer will continue to be able to build using the `github.com/gofrs/uuid/v3` import path using any valid consumer `go.mod` that worked prior to the publishing of v3.2.0, but any module-based consumer should start using the `github.com/gofrs/uuid` import path when possible and _must_ use the `github.com/gofrs/uuid` import path prior to upgrading to v3.2.0.
+
+Please refer to [Issue #61](https://github.com/gofrs/uuid/issues/61) and [Issue #66](https://github.com/gofrs/uuid/issues/66) for more details.
+
+## Usage
+
+Here is a quick overview of how to use this package. For more detailed
+documentation, please see the [GoDoc Page](http://godoc.org/github.com/gofrs/uuid).
+
+```go
+package main
+
+import (
+ "log"
+
+ "github.com/gofrs/uuid"
+)
+
+// Create a Version 4 UUID, panicking on error.
+// Use this form to initialize package-level variables.
+var u1 = uuid.Must(uuid.NewV4())
+
+func main() {
+ // Create a Version 4 UUID.
+ u2, err := uuid.NewV4()
+ if err != nil {
+ log.Fatalf("failed to generate UUID: %v", err)
+ }
+ log.Printf("generated Version 4 UUID %v", u2)
+
+ // Parse a UUID from a string.
+ s := "6ba7b810-9dad-11d1-80b4-00c04fd430c8"
+ u3, err := uuid.FromString(s)
+ if err != nil {
+ log.Fatalf("failed to parse UUID %q: %v", s, err)
+ }
+ log.Printf("successfully parsed UUID %v", u3)
+}
+```
+
+## References
+
+* [RFC-4122](https://tools.ietf.org/html/rfc4122)
+* [DCE 1.1: Authentication and Security Services](http://pubs.opengroup.org/onlinepubs/9696989899/chap5.htm#tagcjh_08_02_01_01)
diff --git a/vendor/github.com/gofrs/uuid/codec.go b/vendor/github.com/gofrs/uuid/codec.go
new file mode 100644
index 0000000..e3d8cfb
--- /dev/null
+++ b/vendor/github.com/gofrs/uuid/codec.go
@@ -0,0 +1,212 @@
+// Copyright (C) 2013-2018 by Maxim Bublis
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+package uuid
+
+import (
+ "bytes"
+ "encoding/hex"
+ "fmt"
+)
+
+// FromBytes returns a UUID generated from the raw byte slice input.
+// It will return an error if the slice isn't 16 bytes long.
+func FromBytes(input []byte) (UUID, error) {
+ u := UUID{}
+ err := u.UnmarshalBinary(input)
+ return u, err
+}
+
+// FromBytesOrNil returns a UUID generated from the raw byte slice input.
+// Same behavior as FromBytes(), but returns uuid.Nil instead of an error.
+func FromBytesOrNil(input []byte) UUID {
+ uuid, err := FromBytes(input)
+ if err != nil {
+ return Nil
+ }
+ return uuid
+}
+
+// FromString returns a UUID parsed from the input string.
+// Input is expected in a form accepted by UnmarshalText.
+func FromString(input string) (UUID, error) {
+ u := UUID{}
+ err := u.UnmarshalText([]byte(input))
+ return u, err
+}
+
+// FromStringOrNil returns a UUID parsed from the input string.
+// Same behavior as FromString(), but returns uuid.Nil instead of an error.
+func FromStringOrNil(input string) UUID {
+ uuid, err := FromString(input)
+ if err != nil {
+ return Nil
+ }
+ return uuid
+}
+
+// MarshalText implements the encoding.TextMarshaler interface.
+// The encoding is the same as returned by the String() method.
+func (u UUID) MarshalText() ([]byte, error) {
+ return []byte(u.String()), nil
+}
+
+// UnmarshalText implements the encoding.TextUnmarshaler interface.
+// Following formats are supported:
+//
+// "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
+// "{6ba7b810-9dad-11d1-80b4-00c04fd430c8}",
+// "urn:uuid:6ba7b810-9dad-11d1-80b4-00c04fd430c8"
+// "6ba7b8109dad11d180b400c04fd430c8"
+// "{6ba7b8109dad11d180b400c04fd430c8}",
+// "urn:uuid:6ba7b8109dad11d180b400c04fd430c8"
+//
+// ABNF for supported UUID text representation follows:
+//
+// URN := 'urn'
+// UUID-NID := 'uuid'
+//
+// hexdig := '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' |
+// 'a' | 'b' | 'c' | 'd' | 'e' | 'f' |
+// 'A' | 'B' | 'C' | 'D' | 'E' | 'F'
+//
+// hexoct := hexdig hexdig
+// 2hexoct := hexoct hexoct
+// 4hexoct := 2hexoct 2hexoct
+// 6hexoct := 4hexoct 2hexoct
+// 12hexoct := 6hexoct 6hexoct
+//
+// hashlike := 12hexoct
+// canonical := 4hexoct '-' 2hexoct '-' 2hexoct '-' 6hexoct
+//
+// plain := canonical | hashlike
+// uuid := canonical | hashlike | braced | urn
+//
+// braced := '{' plain '}' | '{' hashlike '}'
+// urn := URN ':' UUID-NID ':' plain
+//
+func (u *UUID) UnmarshalText(text []byte) error {
+ switch len(text) {
+ case 32:
+ return u.decodeHashLike(text)
+ case 34, 38:
+ return u.decodeBraced(text)
+ case 36:
+ return u.decodeCanonical(text)
+ case 41, 45:
+ return u.decodeURN(text)
+ default:
+ return fmt.Errorf("uuid: incorrect UUID length: %s", text)
+ }
+}
+
+// decodeCanonical decodes UUID strings that are formatted as defined in RFC-4122 (section 3):
+// "6ba7b810-9dad-11d1-80b4-00c04fd430c8".
+func (u *UUID) decodeCanonical(t []byte) error {
+ if t[8] != '-' || t[13] != '-' || t[18] != '-' || t[23] != '-' {
+ return fmt.Errorf("uuid: incorrect UUID format %s", t)
+ }
+
+ src := t
+ dst := u[:]
+
+ for i, byteGroup := range byteGroups {
+ if i > 0 {
+ src = src[1:] // skip dash
+ }
+ _, err := hex.Decode(dst[:byteGroup/2], src[:byteGroup])
+ if err != nil {
+ return err
+ }
+ src = src[byteGroup:]
+ dst = dst[byteGroup/2:]
+ }
+
+ return nil
+}
+
+// decodeHashLike decodes UUID strings that are using the following format:
+// "6ba7b8109dad11d180b400c04fd430c8".
+func (u *UUID) decodeHashLike(t []byte) error {
+ src := t[:]
+ dst := u[:]
+
+ _, err := hex.Decode(dst, src)
+ return err
+}
+
+// decodeBraced decodes UUID strings that are using the following formats:
+// "{6ba7b810-9dad-11d1-80b4-00c04fd430c8}"
+// "{6ba7b8109dad11d180b400c04fd430c8}".
+func (u *UUID) decodeBraced(t []byte) error {
+ l := len(t)
+
+ if t[0] != '{' || t[l-1] != '}' {
+ return fmt.Errorf("uuid: incorrect UUID format %s", t)
+ }
+
+ return u.decodePlain(t[1 : l-1])
+}
+
+// decodeURN decodes UUID strings that are using the following formats:
+// "urn:uuid:6ba7b810-9dad-11d1-80b4-00c04fd430c8"
+// "urn:uuid:6ba7b8109dad11d180b400c04fd430c8".
+func (u *UUID) decodeURN(t []byte) error {
+ total := len(t)
+
+ urnUUIDPrefix := t[:9]
+
+ if !bytes.Equal(urnUUIDPrefix, urnPrefix) {
+ return fmt.Errorf("uuid: incorrect UUID format: %s", t)
+ }
+
+ return u.decodePlain(t[9:total])
+}
+
+// decodePlain decodes UUID strings that are using the following formats:
+// "6ba7b810-9dad-11d1-80b4-00c04fd430c8" or in hash-like format
+// "6ba7b8109dad11d180b400c04fd430c8".
+func (u *UUID) decodePlain(t []byte) error {
+ switch len(t) {
+ case 32:
+ return u.decodeHashLike(t)
+ case 36:
+ return u.decodeCanonical(t)
+ default:
+ return fmt.Errorf("uuid: incorrect UUID length: %s", t)
+ }
+}
+
+// MarshalBinary implements the encoding.BinaryMarshaler interface.
+func (u UUID) MarshalBinary() ([]byte, error) {
+ return u.Bytes(), nil
+}
+
+// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface.
+// It will return an error if the slice isn't 16 bytes long.
+func (u *UUID) UnmarshalBinary(data []byte) error {
+ if len(data) != Size {
+ return fmt.Errorf("uuid: UUID must be exactly 16 bytes long, got %d bytes", len(data))
+ }
+ copy(u[:], data)
+
+ return nil
+}
diff --git a/vendor/github.com/gofrs/uuid/fuzz.go b/vendor/github.com/gofrs/uuid/fuzz.go
new file mode 100644
index 0000000..afaefbc
--- /dev/null
+++ b/vendor/github.com/gofrs/uuid/fuzz.go
@@ -0,0 +1,47 @@
+// Copyright (c) 2018 Andrei Tudor Călin
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+// +build gofuzz
+
+package uuid
+
+// Fuzz implements a simple fuzz test for FromString / UnmarshalText.
+//
+// To run:
+//
+// $ go get github.com/dvyukov/go-fuzz/...
+// $ cd $GOPATH/src/github.com/gofrs/uuid
+// $ go-fuzz-build github.com/gofrs/uuid
+// $ go-fuzz -bin=uuid-fuzz.zip -workdir=./testdata
+//
+// If you make significant changes to FromString / UnmarshalText and add
+// new cases to fromStringTests (in codec_test.go), please run
+//
+// $ go test -seed_fuzz_corpus
+//
+// to seed the corpus with the new interesting inputs, then run the fuzzer.
+func Fuzz(data []byte) int {
+ _, err := FromString(string(data))
+ if err != nil {
+ return 0
+ }
+ return 1
+}
diff --git a/vendor/github.com/gofrs/uuid/generator.go b/vendor/github.com/gofrs/uuid/generator.go
new file mode 100644
index 0000000..4257761
--- /dev/null
+++ b/vendor/github.com/gofrs/uuid/generator.go
@@ -0,0 +1,299 @@
+// Copyright (C) 2013-2018 by Maxim Bublis
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+package uuid
+
+import (
+ "crypto/md5"
+ "crypto/rand"
+ "crypto/sha1"
+ "encoding/binary"
+ "fmt"
+ "hash"
+ "io"
+ "net"
+ "os"
+ "sync"
+ "time"
+)
+
+// Difference in 100-nanosecond intervals between
+// UUID epoch (October 15, 1582) and Unix epoch (January 1, 1970).
+const epochStart = 122192928000000000
+
+type epochFunc func() time.Time
+
+// HWAddrFunc is the function type used to provide hardware (MAC) addresses.
+type HWAddrFunc func() (net.HardwareAddr, error)
+
+// DefaultGenerator is the default UUID Generator used by this package.
+var DefaultGenerator Generator = NewGen()
+
+var (
+ posixUID = uint32(os.Getuid())
+ posixGID = uint32(os.Getgid())
+)
+
+// NewV1 returns a UUID based on the current timestamp and MAC address.
+func NewV1() (UUID, error) {
+ return DefaultGenerator.NewV1()
+}
+
+// NewV2 returns a DCE Security UUID based on the POSIX UID/GID.
+func NewV2(domain byte) (UUID, error) {
+ return DefaultGenerator.NewV2(domain)
+}
+
+// NewV3 returns a UUID based on the MD5 hash of the namespace UUID and name.
+func NewV3(ns UUID, name string) UUID {
+ return DefaultGenerator.NewV3(ns, name)
+}
+
+// NewV4 returns a randomly generated UUID.
+func NewV4() (UUID, error) {
+ return DefaultGenerator.NewV4()
+}
+
+// NewV5 returns a UUID based on SHA-1 hash of the namespace UUID and name.
+func NewV5(ns UUID, name string) UUID {
+ return DefaultGenerator.NewV5(ns, name)
+}
+
+// Generator provides an interface for generating UUIDs.
+type Generator interface {
+ NewV1() (UUID, error)
+ NewV2(domain byte) (UUID, error)
+ NewV3(ns UUID, name string) UUID
+ NewV4() (UUID, error)
+ NewV5(ns UUID, name string) UUID
+}
+
+// Gen is a reference UUID generator based on the specifications laid out in
+// RFC-4122 and DCE 1.1: Authentication and Security Services. This type
+// satisfies the Generator interface as defined in this package.
+//
+// For consumers who are generating V1 UUIDs, but don't want to expose the MAC
+// address of the node generating the UUIDs, the NewGenWithHWAF() function has been
+// provided as a convenience. See the function's documentation for more info.
+//
+// The authors of this package do not feel that the majority of users will need
+// to obfuscate their MAC address, and so we recommend using NewGen() to create
+// a new generator.
+type Gen struct {
+ clockSequenceOnce sync.Once
+ hardwareAddrOnce sync.Once
+ storageMutex sync.Mutex
+
+ rand io.Reader
+
+ epochFunc epochFunc
+ hwAddrFunc HWAddrFunc
+ lastTime uint64
+ clockSequence uint16
+ hardwareAddr [6]byte
+}
+
+// interface check -- build will fail if *Gen doesn't satisfy Generator
+var _ Generator = (*Gen)(nil)
+
+// NewGen returns a new instance of Gen with some default values set. Most
+// people should use this.
+func NewGen() *Gen {
+ return NewGenWithHWAF(defaultHWAddrFunc)
+}
+
+// NewGenWithHWAF builds a new UUID generator with the HWAddrFunc provided. Most
+// consumers should use NewGen() instead.
+//
+// This is used so that consumers can generate their own MAC addresses, for use
+// in the generated UUIDs, if there is some concern about exposing the physical
+// address of the machine generating the UUID.
+//
+// The Gen generator will only invoke the HWAddrFunc once, and cache that MAC
+// address for all the future UUIDs generated by it. If you'd like to switch the
+// MAC address being used, you'll need to create a new generator using this
+// function.
+func NewGenWithHWAF(hwaf HWAddrFunc) *Gen {
+ return &Gen{
+ epochFunc: time.Now,
+ hwAddrFunc: hwaf,
+ rand: rand.Reader,
+ }
+}
+
+// NewV1 returns a UUID based on the current timestamp and MAC address.
+func (g *Gen) NewV1() (UUID, error) {
+ u := UUID{}
+
+ timeNow, clockSeq, err := g.getClockSequence()
+ if err != nil {
+ return Nil, err
+ }
+ binary.BigEndian.PutUint32(u[0:], uint32(timeNow))
+ binary.BigEndian.PutUint16(u[4:], uint16(timeNow>>32))
+ binary.BigEndian.PutUint16(u[6:], uint16(timeNow>>48))
+ binary.BigEndian.PutUint16(u[8:], clockSeq)
+
+ hardwareAddr, err := g.getHardwareAddr()
+ if err != nil {
+ return Nil, err
+ }
+ copy(u[10:], hardwareAddr)
+
+ u.SetVersion(V1)
+ u.SetVariant(VariantRFC4122)
+
+ return u, nil
+}
+
+// NewV2 returns a DCE Security UUID based on the POSIX UID/GID.
+func (g *Gen) NewV2(domain byte) (UUID, error) {
+ u, err := g.NewV1()
+ if err != nil {
+ return Nil, err
+ }
+
+ switch domain {
+ case DomainPerson:
+ binary.BigEndian.PutUint32(u[:], posixUID)
+ case DomainGroup:
+ binary.BigEndian.PutUint32(u[:], posixGID)
+ }
+
+ u[9] = domain
+
+ u.SetVersion(V2)
+ u.SetVariant(VariantRFC4122)
+
+ return u, nil
+}
+
+// NewV3 returns a UUID based on the MD5 hash of the namespace UUID and name.
+func (g *Gen) NewV3(ns UUID, name string) UUID {
+ u := newFromHash(md5.New(), ns, name)
+ u.SetVersion(V3)
+ u.SetVariant(VariantRFC4122)
+
+ return u
+}
+
+// NewV4 returns a randomly generated UUID.
+func (g *Gen) NewV4() (UUID, error) {
+ u := UUID{}
+ if _, err := io.ReadFull(g.rand, u[:]); err != nil {
+ return Nil, err
+ }
+ u.SetVersion(V4)
+ u.SetVariant(VariantRFC4122)
+
+ return u, nil
+}
+
+// NewV5 returns a UUID based on SHA-1 hash of the namespace UUID and name.
+func (g *Gen) NewV5(ns UUID, name string) UUID {
+ u := newFromHash(sha1.New(), ns, name)
+ u.SetVersion(V5)
+ u.SetVariant(VariantRFC4122)
+
+ return u
+}
+
+// Returns the epoch and clock sequence.
+func (g *Gen) getClockSequence() (uint64, uint16, error) {
+ var err error
+ g.clockSequenceOnce.Do(func() {
+ buf := make([]byte, 2)
+ if _, err = io.ReadFull(g.rand, buf); err != nil {
+ return
+ }
+ g.clockSequence = binary.BigEndian.Uint16(buf)
+ })
+ if err != nil {
+ return 0, 0, err
+ }
+
+ g.storageMutex.Lock()
+ defer g.storageMutex.Unlock()
+
+ timeNow := g.getEpoch()
+ // Clock didn't change since last UUID generation.
+ // Should increase clock sequence.
+ if timeNow <= g.lastTime {
+ g.clockSequence++
+ }
+ g.lastTime = timeNow
+
+ return timeNow, g.clockSequence, nil
+}
+
+// Returns the hardware address.
+func (g *Gen) getHardwareAddr() ([]byte, error) {
+ var err error
+ g.hardwareAddrOnce.Do(func() {
+ var hwAddr net.HardwareAddr
+ if hwAddr, err = g.hwAddrFunc(); err == nil {
+ copy(g.hardwareAddr[:], hwAddr)
+ return
+ }
+
+ // Initialize hardwareAddr randomly in case
+ // of real network interfaces absence.
+ if _, err = io.ReadFull(g.rand, g.hardwareAddr[:]); err != nil {
+ return
+ }
+ // Set multicast bit as recommended by RFC-4122
+ g.hardwareAddr[0] |= 0x01
+ })
+ if err != nil {
+ return []byte{}, err
+ }
+ return g.hardwareAddr[:], nil
+}
+
+// Returns the difference between UUID epoch (October 15, 1582)
+// and current time in 100-nanosecond intervals.
+func (g *Gen) getEpoch() uint64 {
+ return epochStart + uint64(g.epochFunc().UnixNano()/100)
+}
+
+// Returns the UUID based on the hashing of the namespace UUID and name.
+func newFromHash(h hash.Hash, ns UUID, name string) UUID {
+ u := UUID{}
+ h.Write(ns[:])
+ h.Write([]byte(name))
+ copy(u[:], h.Sum(nil))
+
+ return u
+}
+
+// Returns the hardware address.
+func defaultHWAddrFunc() (net.HardwareAddr, error) {
+ ifaces, err := net.Interfaces()
+ if err != nil {
+ return []byte{}, err
+ }
+ for _, iface := range ifaces {
+ if len(iface.HardwareAddr) >= 6 {
+ return iface.HardwareAddr, nil
+ }
+ }
+ return []byte{}, fmt.Errorf("uuid: no HW address found")
+}
diff --git a/vendor/github.com/gofrs/uuid/sql.go b/vendor/github.com/gofrs/uuid/sql.go
new file mode 100644
index 0000000..6f254a4
--- /dev/null
+++ b/vendor/github.com/gofrs/uuid/sql.go
@@ -0,0 +1,109 @@
+// Copyright (C) 2013-2018 by Maxim Bublis
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+package uuid
+
+import (
+ "bytes"
+ "database/sql/driver"
+ "encoding/json"
+ "fmt"
+)
+
+// Value implements the driver.Valuer interface.
+func (u UUID) Value() (driver.Value, error) {
+ return u.String(), nil
+}
+
+// Scan implements the sql.Scanner interface.
+// A 16-byte slice will be handled by UnmarshalBinary, while
+// a longer byte slice or a string will be handled by UnmarshalText.
+func (u *UUID) Scan(src interface{}) error {
+ switch src := src.(type) {
+ case UUID: // support gorm convert from UUID to NullUUID
+ *u = src
+ return nil
+
+ case []byte:
+ if len(src) == Size {
+ return u.UnmarshalBinary(src)
+ }
+ return u.UnmarshalText(src)
+
+ case string:
+ return u.UnmarshalText([]byte(src))
+ }
+
+ return fmt.Errorf("uuid: cannot convert %T to UUID", src)
+}
+
+// NullUUID can be used with the standard sql package to represent a
+// UUID value that can be NULL in the database.
+type NullUUID struct {
+ UUID UUID
+ Valid bool
+}
+
+// Value implements the driver.Valuer interface.
+func (u NullUUID) Value() (driver.Value, error) {
+ if !u.Valid {
+ return nil, nil
+ }
+ // Delegate to UUID Value function
+ return u.UUID.Value()
+}
+
+// Scan implements the sql.Scanner interface.
+func (u *NullUUID) Scan(src interface{}) error {
+ if src == nil {
+ u.UUID, u.Valid = Nil, false
+ return nil
+ }
+
+ // Delegate to UUID Scan function
+ u.Valid = true
+ return u.UUID.Scan(src)
+}
+
+// MarshalJSON marshals the NullUUID as null or the nested UUID
+func (u NullUUID) MarshalJSON() ([]byte, error) {
+ if !u.Valid {
+ return json.Marshal(nil)
+ }
+
+ return json.Marshal(u.UUID)
+}
+
+// UnmarshalJSON unmarshals a NullUUID
+func (u *NullUUID) UnmarshalJSON(b []byte) error {
+ if bytes.Equal(b, []byte("null")) {
+ u.UUID, u.Valid = Nil, false
+ return nil
+ }
+
+ if err := json.Unmarshal(b, &u.UUID); err != nil {
+ return err
+ }
+
+ u.Valid = true
+
+ return nil
+}
diff --git a/vendor/github.com/gofrs/uuid/uuid.go b/vendor/github.com/gofrs/uuid/uuid.go
new file mode 100644
index 0000000..29ef440
--- /dev/null
+++ b/vendor/github.com/gofrs/uuid/uuid.go
@@ -0,0 +1,189 @@
+// Copyright (C) 2013-2018 by Maxim Bublis
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+// Package uuid provides implementations of the Universally Unique Identifier (UUID), as specified in RFC-4122 and DCE 1.1.
+//
+// RFC-4122[1] provides the specification for versions 1, 3, 4, and 5.
+//
+// DCE 1.1[2] provides the specification for version 2.
+//
+// [1] https://tools.ietf.org/html/rfc4122
+// [2] http://pubs.opengroup.org/onlinepubs/9696989899/chap5.htm#tagcjh_08_02_01_01
+package uuid
+
+import (
+ "encoding/binary"
+ "encoding/hex"
+ "fmt"
+ "time"
+)
+
+// Size of a UUID in bytes.
+const Size = 16
+
+// UUID is an array type to represent the value of a UUID, as defined in RFC-4122.
+type UUID [Size]byte
+
+// UUID versions.
+const (
+ _ byte = iota
+ V1 // Version 1 (date-time and MAC address)
+ V2 // Version 2 (date-time and MAC address, DCE security version)
+ V3 // Version 3 (namespace name-based)
+ V4 // Version 4 (random)
+ V5 // Version 5 (namespace name-based)
+)
+
+// UUID layout variants.
+const (
+ VariantNCS byte = iota
+ VariantRFC4122
+ VariantMicrosoft
+ VariantFuture
+)
+
+// UUID DCE domains.
+const (
+ DomainPerson = iota
+ DomainGroup
+ DomainOrg
+)
+
+// Timestamp is the count of 100-nanosecond intervals since 00:00:00.00,
+// 15 October 1582 within a V1 UUID. This type has no meaning for V2-V5
+// UUIDs since they don't have an embedded timestamp.
+type Timestamp uint64
+
+const _100nsPerSecond = 10000000
+
+// Time returns the UTC time.Time representation of a Timestamp
+func (t Timestamp) Time() (time.Time, error) {
+ secs := uint64(t) / _100nsPerSecond
+ nsecs := 100 * (uint64(t) % _100nsPerSecond)
+ return time.Unix(int64(secs)-(epochStart/_100nsPerSecond), int64(nsecs)), nil
+}
+
+// TimestampFromV1 returns the Timestamp embedded within a V1 UUID.
+// Returns an error if the UUID is any version other than 1.
+func TimestampFromV1(u UUID) (Timestamp, error) {
+ if u.Version() != 1 {
+ err := fmt.Errorf("uuid: %s is version %d, not version 1", u, u.Version())
+ return 0, err
+ }
+ low := binary.BigEndian.Uint32(u[0:4])
+ mid := binary.BigEndian.Uint16(u[4:6])
+ hi := binary.BigEndian.Uint16(u[6:8]) & 0xfff
+ return Timestamp(uint64(low) + (uint64(mid) << 32) + (uint64(hi) << 48)), nil
+}
+
+// String parse helpers.
+var (
+ urnPrefix = []byte("urn:uuid:")
+ byteGroups = []int{8, 4, 4, 4, 12}
+)
+
+// Nil is the nil UUID, as specified in RFC-4122, that has all 128 bits set to
+// zero.
+var Nil = UUID{}
+
+// Predefined namespace UUIDs.
+var (
+ NamespaceDNS = Must(FromString("6ba7b810-9dad-11d1-80b4-00c04fd430c8"))
+ NamespaceURL = Must(FromString("6ba7b811-9dad-11d1-80b4-00c04fd430c8"))
+ NamespaceOID = Must(FromString("6ba7b812-9dad-11d1-80b4-00c04fd430c8"))
+ NamespaceX500 = Must(FromString("6ba7b814-9dad-11d1-80b4-00c04fd430c8"))
+)
+
+// Version returns the algorithm version used to generate the UUID.
+func (u UUID) Version() byte {
+ return u[6] >> 4
+}
+
+// Variant returns the UUID layout variant.
+func (u UUID) Variant() byte {
+ switch {
+ case (u[8] >> 7) == 0x00:
+ return VariantNCS
+ case (u[8] >> 6) == 0x02:
+ return VariantRFC4122
+ case (u[8] >> 5) == 0x06:
+ return VariantMicrosoft
+ case (u[8] >> 5) == 0x07:
+ fallthrough
+ default:
+ return VariantFuture
+ }
+}
+
+// Bytes returns a byte slice representation of the UUID.
+func (u UUID) Bytes() []byte {
+ return u[:]
+}
+
+// String returns a canonical RFC-4122 string representation of the UUID:
+// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.
+func (u UUID) String() string {
+ buf := make([]byte, 36)
+
+ hex.Encode(buf[0:8], u[0:4])
+ buf[8] = '-'
+ hex.Encode(buf[9:13], u[4:6])
+ buf[13] = '-'
+ hex.Encode(buf[14:18], u[6:8])
+ buf[18] = '-'
+ hex.Encode(buf[19:23], u[8:10])
+ buf[23] = '-'
+ hex.Encode(buf[24:], u[10:])
+
+ return string(buf)
+}
+
+// SetVersion sets the version bits.
+func (u *UUID) SetVersion(v byte) {
+ u[6] = (u[6] & 0x0f) | (v << 4)
+}
+
+// SetVariant sets the variant bits.
+func (u *UUID) SetVariant(v byte) {
+ switch v {
+ case VariantNCS:
+ u[8] = (u[8]&(0xff>>1) | (0x00 << 7))
+ case VariantRFC4122:
+ u[8] = (u[8]&(0xff>>2) | (0x02 << 6))
+ case VariantMicrosoft:
+ u[8] = (u[8]&(0xff>>3) | (0x06 << 5))
+ case VariantFuture:
+ fallthrough
+ default:
+ u[8] = (u[8]&(0xff>>3) | (0x07 << 5))
+ }
+}
+
+// Must is a helper that wraps a call to a function returning (UUID, error)
+// and panics if the error is non-nil. It is intended for use in variable
+// initializations such as
+// var packageUUID = uuid.Must(uuid.FromString("123e4567-e89b-12d3-a456-426655440000"))
+func Must(u UUID, err error) UUID {
+ if err != nil {
+ panic(err)
+ }
+ return u
+}
diff --git a/vendor/github.com/gorilla/mux/.travis.yml b/vendor/github.com/gorilla/mux/.travis.yml
deleted file mode 100644
index ca377e6..0000000
--- a/vendor/github.com/gorilla/mux/.travis.yml
+++ /dev/null
@@ -1,22 +0,0 @@
-language: go
-sudo: false
-
-matrix:
- include:
- - go: 1.2
- - go: 1.3
- - go: 1.4
- - go: 1.5
- - go: 1.6
- - go: 1.7
- - go: 1.8
- - go: tip
-
-install:
- - # Skip
-
-script:
- - go get -t -v ./...
- - diff -u <(echo -n) <(gofmt -d .)
- - go tool vet .
- - go test -v -race ./...
diff --git a/vendor/github.com/gorilla/mux/AUTHORS b/vendor/github.com/gorilla/mux/AUTHORS
new file mode 100644
index 0000000..b722392
--- /dev/null
+++ b/vendor/github.com/gorilla/mux/AUTHORS
@@ -0,0 +1,8 @@
+# This is the official list of gorilla/mux authors for copyright purposes.
+#
+# Please keep the list sorted.
+
+Google LLC (https://opensource.google.com/)
+Kamil Kisielk
+Matt Silverlock
+Rodrigo Moraes (https://github.com/moraes)
diff --git a/vendor/github.com/gorilla/mux/LICENSE b/vendor/github.com/gorilla/mux/LICENSE
index 0e5fb87..6903df6 100644
--- a/vendor/github.com/gorilla/mux/LICENSE
+++ b/vendor/github.com/gorilla/mux/LICENSE
@@ -1,4 +1,4 @@
-Copyright (c) 2012 Rodrigo Moraes. All rights reserved.
+Copyright (c) 2012-2018 The Gorilla Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
diff --git a/vendor/github.com/gorilla/mux/README.md b/vendor/github.com/gorilla/mux/README.md
index b096bf6..92e422e 100644
--- a/vendor/github.com/gorilla/mux/README.md
+++ b/vendor/github.com/gorilla/mux/README.md
@@ -1,12 +1,13 @@
-gorilla/mux
-===
+# gorilla/mux
+
[](https://godoc.org/github.com/gorilla/mux)
[](https://travis-ci.org/gorilla/mux)
+[](https://circleci.com/gh/gorilla/mux)
[](https://sourcegraph.com/github.com/gorilla/mux?badge)

-http://www.gorillatoolkit.org/pkg/mux
+https://www.gorillatoolkit.org/pkg/mux
Package `gorilla/mux` implements a request router and dispatcher for matching incoming requests to
their respective handler.
@@ -27,6 +28,10 @@ The name mux stands for "HTTP request multiplexer". Like the standard `http.Serv
* [Static Files](#static-files)
* [Registered URLs](#registered-urls)
* [Walking Routes](#walking-routes)
+* [Graceful Shutdown](#graceful-shutdown)
+* [Middleware](#middleware)
+* [Handling CORS Requests](#handling-cors-requests)
+* [Testing Handlers](#testing-handlers)
* [Full Example](#full-example)
---
@@ -45,11 +50,11 @@ Let's start registering a couple of URL paths and handlers:
```go
func main() {
- r := mux.NewRouter()
- r.HandleFunc("/", HomeHandler)
- r.HandleFunc("/products", ProductsHandler)
- r.HandleFunc("/articles", ArticlesHandler)
- http.Handle("/", r)
+ r := mux.NewRouter()
+ r.HandleFunc("/", HomeHandler)
+ r.HandleFunc("/products", ProductsHandler)
+ r.HandleFunc("/articles", ArticlesHandler)
+ http.Handle("/", r)
}
```
@@ -68,9 +73,9 @@ The names are used to create a map of route variables which can be retrieved cal
```go
func ArticlesCategoryHandler(w http.ResponseWriter, r *http.Request) {
- vars := mux.Vars(r)
- w.WriteHeader(http.StatusOK)
- fmt.Fprintf(w, "Category: %v\n", vars["category"])
+ vars := mux.Vars(r)
+ w.WriteHeader(http.StatusOK)
+ fmt.Fprintf(w, "Category: %v\n", vars["category"])
}
```
@@ -85,7 +90,7 @@ r := mux.NewRouter()
// Only matches if domain is "www.example.com".
r.Host("www.example.com")
// Matches a dynamic subdomain.
-r.Host("{subdomain:[a-z]+}.domain.com")
+r.Host("{subdomain:[a-z]+}.example.com")
```
There are several other matchers that can be added. To match path prefixes:
@@ -122,7 +127,7 @@ r.Queries("key", "value")
```go
r.MatcherFunc(func(r *http.Request, rm *RouteMatch) bool {
- return r.ProtoMajor == 0
+ return r.ProtoMajor == 0
})
```
@@ -176,79 +181,34 @@ s.HandleFunc("/{key}/", ProductHandler)
// "/products/{key}/details"
s.HandleFunc("/{key}/details", ProductDetailsHandler)
```
-### Listing Routes
-Routes on a mux can be listed using the Router.Walk method—useful for generating documentation:
-
-```go
-package main
-
-import (
- "fmt"
- "net/http"
- "strings"
-
- "github.com/gorilla/mux"
-)
-
-func handler(w http.ResponseWriter, r *http.Request) {
- return
-}
-
-func main() {
- r := mux.NewRouter()
- r.HandleFunc("/", handler)
- r.HandleFunc("/products", handler).Methods("POST")
- r.HandleFunc("/articles", handler).Methods("GET")
- r.HandleFunc("/articles/{id}", handler).Methods("GET", "PUT")
- r.Walk(func(route *mux.Route, router *mux.Router, ancestors []*mux.Route) error {
- t, err := route.GetPathTemplate()
- if err != nil {
- return err
- }
- // p will contain regular expression is compatible with regular expression in Perl, Python, and other languages.
- // for instance the regular expression for path '/articles/{id}' will be '^/articles/(?P[^/]+)$'
- p, err := route.GetPathRegexp()
- if err != nil {
- return err
- }
- m, err := route.GetMethods()
- if err != nil {
- return err
- }
- fmt.Println(strings.Join(m, ","), t, p)
- return nil
- })
- http.Handle("/", r)
-}
-```
### Static Files
Note that the path provided to `PathPrefix()` represents a "wildcard": calling
`PathPrefix("/static/").Handler(...)` means that the handler will be passed any
-request that matches "/static/*". This makes it easy to serve static files with mux:
+request that matches "/static/\*". This makes it easy to serve static files with mux:
```go
func main() {
- var dir string
+ var dir string
- flag.StringVar(&dir, "dir", ".", "the directory to serve files from. Defaults to the current dir")
- flag.Parse()
- r := mux.NewRouter()
+ flag.StringVar(&dir, "dir", ".", "the directory to serve files from. Defaults to the current dir")
+ flag.Parse()
+ r := mux.NewRouter()
- // This will serve files under http://localhost:8000/static/
- r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir(dir))))
+ // This will serve files under http://localhost:8000/static/
+ r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir(dir))))
- srv := &http.Server{
- Handler: r,
- Addr: "127.0.0.1:8000",
- // Good practice: enforce timeouts for servers you create!
- WriteTimeout: 15 * time.Second,
- ReadTimeout: 15 * time.Second,
- }
+ srv := &http.Server{
+ Handler: r,
+ Addr: "127.0.0.1:8000",
+ // Good practice: enforce timeouts for servers you create!
+ WriteTimeout: 15 * time.Second,
+ ReadTimeout: 15 * time.Second,
+ }
- log.Fatal(srv.ListenAndServe())
+ log.Fatal(srv.ListenAndServe())
}
```
@@ -280,13 +240,13 @@ This also works for host and query value variables:
```go
r := mux.NewRouter()
-r.Host("{subdomain}.domain.com").
+r.Host("{subdomain}.example.com").
Path("/articles/{category}/{id:[0-9]+}").
Queries("filter", "{filter}").
HandlerFunc(ArticleHandler).
Name("article")
-// url.String() will be "http://news.domain.com/articles/technology/42?filter=gorilla"
+// url.String() will be "http://news.example.com/articles/technology/42?filter=gorilla"
url, err := r.Get("article").URL("subdomain", "news",
"category", "technology",
"id", "42",
@@ -306,7 +266,7 @@ r.HeadersRegexp("Content-Type", "application/(text|json)")
There's also a way to build only the URL host or path for a route: use the methods `URLHost()` or `URLPath()` instead. For the previous route, we would do:
```go
-// "http://news.domain.com/"
+// "http://news.example.com/"
host, err := r.Get("article").URLHost("subdomain", "news")
// "/articles/technology/42"
@@ -317,12 +277,12 @@ And if you use subrouters, host and path defined separately can be built as well
```go
r := mux.NewRouter()
-s := r.Host("{subdomain}.domain.com").Subrouter()
+s := r.Host("{subdomain}.example.com").Subrouter()
s.Path("/articles/{category}/{id:[0-9]+}").
HandlerFunc(ArticleHandler).
Name("article")
-// "http://news.domain.com/articles/technology/42"
+// "http://news.example.com/articles/technology/42"
url, err := r.Get("article").URL("subdomain", "news",
"category", "technology",
"id", "42")
@@ -333,30 +293,397 @@ url, err := r.Get("article").URL("subdomain", "news",
The `Walk` function on `mux.Router` can be used to visit all of the routes that are registered on a router. For example,
the following prints all of the registered routes:
+```go
+package main
+
+import (
+ "fmt"
+ "net/http"
+ "strings"
+
+ "github.com/gorilla/mux"
+)
+
+func handler(w http.ResponseWriter, r *http.Request) {
+ return
+}
+
+func main() {
+ r := mux.NewRouter()
+ r.HandleFunc("/", handler)
+ r.HandleFunc("/products", handler).Methods("POST")
+ r.HandleFunc("/articles", handler).Methods("GET")
+ r.HandleFunc("/articles/{id}", handler).Methods("GET", "PUT")
+ r.HandleFunc("/authors", handler).Queries("surname", "{surname}")
+ err := r.Walk(func(route *mux.Route, router *mux.Router, ancestors []*mux.Route) error {
+ pathTemplate, err := route.GetPathTemplate()
+ if err == nil {
+ fmt.Println("ROUTE:", pathTemplate)
+ }
+ pathRegexp, err := route.GetPathRegexp()
+ if err == nil {
+ fmt.Println("Path regexp:", pathRegexp)
+ }
+ queriesTemplates, err := route.GetQueriesTemplates()
+ if err == nil {
+ fmt.Println("Queries templates:", strings.Join(queriesTemplates, ","))
+ }
+ queriesRegexps, err := route.GetQueriesRegexp()
+ if err == nil {
+ fmt.Println("Queries regexps:", strings.Join(queriesRegexps, ","))
+ }
+ methods, err := route.GetMethods()
+ if err == nil {
+ fmt.Println("Methods:", strings.Join(methods, ","))
+ }
+ fmt.Println()
+ return nil
+ })
+
+ if err != nil {
+ fmt.Println(err)
+ }
+
+ http.Handle("/", r)
+}
+```
+
+### Graceful Shutdown
+
+Go 1.8 introduced the ability to [gracefully shutdown](https://golang.org/doc/go1.8#http_shutdown) a `*http.Server`. Here's how to do that alongside `mux`:
+
+```go
+package main
+
+import (
+ "context"
+ "flag"
+ "log"
+ "net/http"
+ "os"
+ "os/signal"
+ "time"
+
+ "github.com/gorilla/mux"
+)
+
+func main() {
+ var wait time.Duration
+ flag.DurationVar(&wait, "graceful-timeout", time.Second * 15, "the duration for which the server gracefully wait for existing connections to finish - e.g. 15s or 1m")
+ flag.Parse()
+
+ r := mux.NewRouter()
+ // Add your routes as needed
+
+ srv := &http.Server{
+ Addr: "0.0.0.0:8080",
+ // Good practice to set timeouts to avoid Slowloris attacks.
+ WriteTimeout: time.Second * 15,
+ ReadTimeout: time.Second * 15,
+ IdleTimeout: time.Second * 60,
+ Handler: r, // Pass our instance of gorilla/mux in.
+ }
+
+ // Run our server in a goroutine so that it doesn't block.
+ go func() {
+ if err := srv.ListenAndServe(); err != nil {
+ log.Println(err)
+ }
+ }()
+
+ c := make(chan os.Signal, 1)
+ // We'll accept graceful shutdowns when quit via SIGINT (Ctrl+C)
+ // SIGKILL, SIGQUIT or SIGTERM (Ctrl+/) will not be caught.
+ signal.Notify(c, os.Interrupt)
+
+ // Block until we receive our signal.
+ <-c
+
+ // Create a deadline to wait for.
+ ctx, cancel := context.WithTimeout(context.Background(), wait)
+ defer cancel()
+ // Doesn't block if no connections, but will otherwise wait
+ // until the timeout deadline.
+ srv.Shutdown(ctx)
+ // Optionally, you could run srv.Shutdown in a goroutine and block on
+ // <-ctx.Done() if your application should wait for other services
+ // to finalize based on context cancellation.
+ log.Println("shutting down")
+ os.Exit(0)
+}
+```
+
+### Middleware
+
+Mux supports the addition of middlewares to a [Router](https://godoc.org/github.com/gorilla/mux#Router), which are executed in the order they are added if a match is found, including its subrouters.
+Middlewares are (typically) small pieces of code which take one request, do something with it, and pass it down to another middleware or the final handler. Some common use cases for middleware are request logging, header manipulation, or `ResponseWriter` hijacking.
+
+Mux middlewares are defined using the de facto standard type:
+
+```go
+type MiddlewareFunc func(http.Handler) http.Handler
+```
+
+Typically, the returned handler is a closure which does something with the http.ResponseWriter and http.Request passed to it, and then calls the handler passed as parameter to the MiddlewareFunc. This takes advantage of closures being able access variables from the context where they are created, while retaining the signature enforced by the receivers.
+
+A very basic middleware which logs the URI of the request being handled could be written as:
+
+```go
+func loggingMiddleware(next http.Handler) http.Handler {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ // Do stuff here
+ log.Println(r.RequestURI)
+ // Call the next handler, which can be another middleware in the chain, or the final handler.
+ next.ServeHTTP(w, r)
+ })
+}
+```
+
+Middlewares can be added to a router using `Router.Use()`:
+
```go
r := mux.NewRouter()
r.HandleFunc("/", handler)
-r.HandleFunc("/products", handler).Methods("POST")
-r.HandleFunc("/articles", handler).Methods("GET")
-r.HandleFunc("/articles/{id}", handler).Methods("GET", "PUT")
-r.Walk(func(route *mux.Route, router *mux.Router, ancestors []*mux.Route) error {
- t, err := route.GetPathTemplate()
- if err != nil {
- return err
+r.Use(loggingMiddleware)
+```
+
+A more complex authentication middleware, which maps session token to users, could be written as:
+
+```go
+// Define our struct
+type authenticationMiddleware struct {
+ tokenUsers map[string]string
+}
+
+// Initialize it somewhere
+func (amw *authenticationMiddleware) Populate() {
+ amw.tokenUsers["00000000"] = "user0"
+ amw.tokenUsers["aaaaaaaa"] = "userA"
+ amw.tokenUsers["05f717e5"] = "randomUser"
+ amw.tokenUsers["deadbeef"] = "user0"
+}
+
+// Middleware function, which will be called for each request
+func (amw *authenticationMiddleware) Middleware(next http.Handler) http.Handler {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ token := r.Header.Get("X-Session-Token")
+
+ if user, found := amw.tokenUsers[token]; found {
+ // We found the token in our map
+ log.Printf("Authenticated user %s\n", user)
+ // Pass down the request to the next middleware (or final handler)
+ next.ServeHTTP(w, r)
+ } else {
+ // Write an error and stop the handler chain
+ http.Error(w, "Forbidden", http.StatusForbidden)
+ }
+ })
+}
+```
+
+```go
+r := mux.NewRouter()
+r.HandleFunc("/", handler)
+
+amw := authenticationMiddleware{}
+amw.Populate()
+
+r.Use(amw.Middleware)
+```
+
+Note: The handler chain will be stopped if your middleware doesn't call `next.ServeHTTP()` with the corresponding parameters. This can be used to abort a request if the middleware writer wants to. Middlewares _should_ write to `ResponseWriter` if they _are_ going to terminate the request, and they _should not_ write to `ResponseWriter` if they _are not_ going to terminate it.
+
+### Handling CORS Requests
+
+[CORSMethodMiddleware](https://godoc.org/github.com/gorilla/mux#CORSMethodMiddleware) intends to make it easier to strictly set the `Access-Control-Allow-Methods` response header.
+
+* You will still need to use your own CORS handler to set the other CORS headers such as `Access-Control-Allow-Origin`
+* The middleware will set the `Access-Control-Allow-Methods` header to all the method matchers (e.g. `r.Methods(http.MethodGet, http.MethodPut, http.MethodOptions)` -> `Access-Control-Allow-Methods: GET,PUT,OPTIONS`) on a route
+* If you do not specify any methods, then:
+> _Important_: there must be an `OPTIONS` method matcher for the middleware to set the headers.
+
+Here is an example of using `CORSMethodMiddleware` along with a custom `OPTIONS` handler to set all the required CORS headers:
+
+```go
+package main
+
+import (
+ "net/http"
+ "github.com/gorilla/mux"
+)
+
+func main() {
+ r := mux.NewRouter()
+
+ // IMPORTANT: you must specify an OPTIONS method matcher for the middleware to set CORS headers
+ r.HandleFunc("/foo", fooHandler).Methods(http.MethodGet, http.MethodPut, http.MethodPatch, http.MethodOptions)
+ r.Use(mux.CORSMethodMiddleware(r))
+
+ http.ListenAndServe(":8080", r)
+}
+
+func fooHandler(w http.ResponseWriter, r *http.Request) {
+ w.Header().Set("Access-Control-Allow-Origin", "*")
+ if r.Method == http.MethodOptions {
+ return
}
- // p will contain a regular expression that is compatible with regular expressions in Perl, Python, and other languages.
- // For example, the regular expression for path '/articles/{id}' will be '^/articles/(?P[^/]+)$'.
- p, err := route.GetPathRegexp()
+
+ w.Write([]byte("foo"))
+}
+```
+
+And an request to `/foo` using something like:
+
+```bash
+curl localhost:8080/foo -v
+```
+
+Would look like:
+
+```bash
+* Trying ::1...
+* TCP_NODELAY set
+* Connected to localhost (::1) port 8080 (#0)
+> GET /foo HTTP/1.1
+> Host: localhost:8080
+> User-Agent: curl/7.59.0
+> Accept: */*
+>
+< HTTP/1.1 200 OK
+< Access-Control-Allow-Methods: GET,PUT,PATCH,OPTIONS
+< Access-Control-Allow-Origin: *
+< Date: Fri, 28 Jun 2019 20:13:30 GMT
+< Content-Length: 3
+< Content-Type: text/plain; charset=utf-8
+<
+* Connection #0 to host localhost left intact
+foo
+```
+
+### Testing Handlers
+
+Testing handlers in a Go web application is straightforward, and _mux_ doesn't complicate this any further. Given two files: `endpoints.go` and `endpoints_test.go`, here's how we'd test an application using _mux_.
+
+First, our simple HTTP handler:
+
+```go
+// endpoints.go
+package main
+
+func HealthCheckHandler(w http.ResponseWriter, r *http.Request) {
+ // A very simple health check.
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(http.StatusOK)
+
+ // In the future we could report back on the status of our DB, or our cache
+ // (e.g. Redis) by performing a simple PING, and include them in the response.
+ io.WriteString(w, `{"alive": true}`)
+}
+
+func main() {
+ r := mux.NewRouter()
+ r.HandleFunc("/health", HealthCheckHandler)
+
+ log.Fatal(http.ListenAndServe("localhost:8080", r))
+}
+```
+
+Our test code:
+
+```go
+// endpoints_test.go
+package main
+
+import (
+ "net/http"
+ "net/http/httptest"
+ "testing"
+)
+
+func TestHealthCheckHandler(t *testing.T) {
+ // Create a request to pass to our handler. We don't have any query parameters for now, so we'll
+ // pass 'nil' as the third parameter.
+ req, err := http.NewRequest("GET", "/health", nil)
if err != nil {
- return err
+ t.Fatal(err)
}
- m, err := route.GetMethods()
- if err != nil {
- return err
+
+ // We create a ResponseRecorder (which satisfies http.ResponseWriter) to record the response.
+ rr := httptest.NewRecorder()
+ handler := http.HandlerFunc(HealthCheckHandler)
+
+ // Our handlers satisfy http.Handler, so we can call their ServeHTTP method
+ // directly and pass in our Request and ResponseRecorder.
+ handler.ServeHTTP(rr, req)
+
+ // Check the status code is what we expect.
+ if status := rr.Code; status != http.StatusOK {
+ t.Errorf("handler returned wrong status code: got %v want %v",
+ status, http.StatusOK)
}
- fmt.Println(strings.Join(m, ","), t, p)
- return nil
-})
+
+ // Check the response body is what we expect.
+ expected := `{"alive": true}`
+ if rr.Body.String() != expected {
+ t.Errorf("handler returned unexpected body: got %v want %v",
+ rr.Body.String(), expected)
+ }
+}
+```
+
+In the case that our routes have [variables](#examples), we can pass those in the request. We could write
+[table-driven tests](https://dave.cheney.net/2013/06/09/writing-table-driven-tests-in-go) to test multiple
+possible route variables as needed.
+
+```go
+// endpoints.go
+func main() {
+ r := mux.NewRouter()
+ // A route with a route variable:
+ r.HandleFunc("/metrics/{type}", MetricsHandler)
+
+ log.Fatal(http.ListenAndServe("localhost:8080", r))
+}
+```
+
+Our test file, with a table-driven test of `routeVariables`:
+
+```go
+// endpoints_test.go
+func TestMetricsHandler(t *testing.T) {
+ tt := []struct{
+ routeVariable string
+ shouldPass bool
+ }{
+ {"goroutines", true},
+ {"heap", true},
+ {"counters", true},
+ {"queries", true},
+ {"adhadaeqm3k", false},
+ }
+
+ for _, tc := range tt {
+ path := fmt.Sprintf("/metrics/%s", tc.routeVariable)
+ req, err := http.NewRequest("GET", path, nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ rr := httptest.NewRecorder()
+
+ // Need to create a router that we can pass the request through so that the vars will be added to the context
+ router := mux.NewRouter()
+ router.HandleFunc("/metrics/{type}", MetricsHandler)
+ router.ServeHTTP(rr, req)
+
+ // In this case, our MetricsHandler returns a non-200 response
+ // for a route variable it doesn't know about.
+ if rr.Code == http.StatusOK && !tc.shouldPass {
+ t.Errorf("handler should have failed on routeVariable %s: got %v want %v",
+ tc.routeVariable, rr.Code, http.StatusOK)
+ }
+ }
+}
```
## Full Example
@@ -367,22 +694,22 @@ Here's a complete, runnable example of a small `mux` based server:
package main
import (
- "net/http"
- "log"
- "github.com/gorilla/mux"
+ "net/http"
+ "log"
+ "github.com/gorilla/mux"
)
func YourHandler(w http.ResponseWriter, r *http.Request) {
- w.Write([]byte("Gorilla!\n"))
+ w.Write([]byte("Gorilla!\n"))
}
func main() {
- r := mux.NewRouter()
- // Routes consist of a path and a handler function.
- r.HandleFunc("/", YourHandler)
+ r := mux.NewRouter()
+ // Routes consist of a path and a handler function.
+ r.HandleFunc("/", YourHandler)
- // Bind to a port and pass our router in
- log.Fatal(http.ListenAndServe(":8000", r))
+ // Bind to a port and pass our router in
+ log.Fatal(http.ListenAndServe(":8000", r))
}
```
diff --git a/vendor/github.com/gorilla/mux/context_native.go b/vendor/github.com/gorilla/mux/context.go
similarity index 82%
rename from vendor/github.com/gorilla/mux/context_native.go
rename to vendor/github.com/gorilla/mux/context.go
index 209cbea..665940a 100644
--- a/vendor/github.com/gorilla/mux/context_native.go
+++ b/vendor/github.com/gorilla/mux/context.go
@@ -1,5 +1,3 @@
-// +build go1.7
-
package mux
import (
@@ -18,7 +16,3 @@ func contextSet(r *http.Request, key, val interface{}) *http.Request {
return r.WithContext(context.WithValue(r.Context(), key, val))
}
-
-func contextClear(r *http.Request) {
- return
-}
diff --git a/vendor/github.com/gorilla/mux/context_gorilla.go b/vendor/github.com/gorilla/mux/context_gorilla.go
deleted file mode 100644
index d7adaa8..0000000
--- a/vendor/github.com/gorilla/mux/context_gorilla.go
+++ /dev/null
@@ -1,26 +0,0 @@
-// +build !go1.7
-
-package mux
-
-import (
- "net/http"
-
- "github.com/gorilla/context"
-)
-
-func contextGet(r *http.Request, key interface{}) interface{} {
- return context.Get(r, key)
-}
-
-func contextSet(r *http.Request, key, val interface{}) *http.Request {
- if val == nil {
- return r
- }
-
- context.Set(r, key, val)
- return r
-}
-
-func contextClear(r *http.Request) {
- context.Clear(r)
-}
diff --git a/vendor/github.com/gorilla/mux/doc.go b/vendor/github.com/gorilla/mux/doc.go
index cce30b2..bd5a38b 100644
--- a/vendor/github.com/gorilla/mux/doc.go
+++ b/vendor/github.com/gorilla/mux/doc.go
@@ -238,5 +238,69 @@ as well:
url, err := r.Get("article").URL("subdomain", "news",
"category", "technology",
"id", "42")
+
+Mux supports the addition of middlewares to a Router, which are executed in the order they are added if a match is found, including its subrouters. Middlewares are (typically) small pieces of code which take one request, do something with it, and pass it down to another middleware or the final handler. Some common use cases for middleware are request logging, header manipulation, or ResponseWriter hijacking.
+
+ type MiddlewareFunc func(http.Handler) http.Handler
+
+Typically, the returned handler is a closure which does something with the http.ResponseWriter and http.Request passed to it, and then calls the handler passed as parameter to the MiddlewareFunc (closures can access variables from the context where they are created).
+
+A very basic middleware which logs the URI of the request being handled could be written as:
+
+ func simpleMw(next http.Handler) http.Handler {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ // Do stuff here
+ log.Println(r.RequestURI)
+ // Call the next handler, which can be another middleware in the chain, or the final handler.
+ next.ServeHTTP(w, r)
+ })
+ }
+
+Middlewares can be added to a router using `Router.Use()`:
+
+ r := mux.NewRouter()
+ r.HandleFunc("/", handler)
+ r.Use(simpleMw)
+
+A more complex authentication middleware, which maps session token to users, could be written as:
+
+ // Define our struct
+ type authenticationMiddleware struct {
+ tokenUsers map[string]string
+ }
+
+ // Initialize it somewhere
+ func (amw *authenticationMiddleware) Populate() {
+ amw.tokenUsers["00000000"] = "user0"
+ amw.tokenUsers["aaaaaaaa"] = "userA"
+ amw.tokenUsers["05f717e5"] = "randomUser"
+ amw.tokenUsers["deadbeef"] = "user0"
+ }
+
+ // Middleware function, which will be called for each request
+ func (amw *authenticationMiddleware) Middleware(next http.Handler) http.Handler {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ token := r.Header.Get("X-Session-Token")
+
+ if user, found := amw.tokenUsers[token]; found {
+ // We found the token in our map
+ log.Printf("Authenticated user %s\n", user)
+ next.ServeHTTP(w, r)
+ } else {
+ http.Error(w, "Forbidden", http.StatusForbidden)
+ }
+ })
+ }
+
+ r := mux.NewRouter()
+ r.HandleFunc("/", handler)
+
+ amw := authenticationMiddleware{tokenUsers: make(map[string]string)}
+ amw.Populate()
+
+ r.Use(amw.Middleware)
+
+Note: The handler chain will be stopped if your middleware doesn't call `next.ServeHTTP()` with the corresponding parameters. This can be used to abort a request if the middleware writer wants to.
+
*/
package mux
diff --git a/vendor/github.com/gorilla/mux/go.mod b/vendor/github.com/gorilla/mux/go.mod
new file mode 100644
index 0000000..cfc8ede
--- /dev/null
+++ b/vendor/github.com/gorilla/mux/go.mod
@@ -0,0 +1 @@
+module github.com/gorilla/mux
diff --git a/vendor/github.com/gorilla/mux/middleware.go b/vendor/github.com/gorilla/mux/middleware.go
new file mode 100644
index 0000000..cf2b26d
--- /dev/null
+++ b/vendor/github.com/gorilla/mux/middleware.go
@@ -0,0 +1,79 @@
+package mux
+
+import (
+ "net/http"
+ "strings"
+)
+
+// MiddlewareFunc is a function which receives an http.Handler and returns another http.Handler.
+// Typically, the returned handler is a closure which does something with the http.ResponseWriter and http.Request passed
+// to it, and then calls the handler passed as parameter to the MiddlewareFunc.
+type MiddlewareFunc func(http.Handler) http.Handler
+
+// middleware interface is anything which implements a MiddlewareFunc named Middleware.
+type middleware interface {
+ Middleware(handler http.Handler) http.Handler
+}
+
+// Middleware allows MiddlewareFunc to implement the middleware interface.
+func (mw MiddlewareFunc) Middleware(handler http.Handler) http.Handler {
+ return mw(handler)
+}
+
+// Use appends a MiddlewareFunc to the chain. Middleware can be used to intercept or otherwise modify requests and/or responses, and are executed in the order that they are applied to the Router.
+func (r *Router) Use(mwf ...MiddlewareFunc) {
+ for _, fn := range mwf {
+ r.middlewares = append(r.middlewares, fn)
+ }
+}
+
+// useInterface appends a middleware to the chain. Middleware can be used to intercept or otherwise modify requests and/or responses, and are executed in the order that they are applied to the Router.
+func (r *Router) useInterface(mw middleware) {
+ r.middlewares = append(r.middlewares, mw)
+}
+
+// CORSMethodMiddleware automatically sets the Access-Control-Allow-Methods response header
+// on requests for routes that have an OPTIONS method matcher to all the method matchers on
+// the route. Routes that do not explicitly handle OPTIONS requests will not be processed
+// by the middleware. See examples for usage.
+func CORSMethodMiddleware(r *Router) MiddlewareFunc {
+ return func(next http.Handler) http.Handler {
+ return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
+ allMethods, err := getAllMethodsForRoute(r, req)
+ if err == nil {
+ for _, v := range allMethods {
+ if v == http.MethodOptions {
+ w.Header().Set("Access-Control-Allow-Methods", strings.Join(allMethods, ","))
+ }
+ }
+ }
+
+ next.ServeHTTP(w, req)
+ })
+ }
+}
+
+// getAllMethodsForRoute returns all the methods from method matchers matching a given
+// request.
+func getAllMethodsForRoute(r *Router, req *http.Request) ([]string, error) {
+ var allMethods []string
+
+ err := r.Walk(func(route *Route, _ *Router, _ []*Route) error {
+ for _, m := range route.matchers {
+ if _, ok := m.(*routeRegexp); ok {
+ if m.Match(req, &RouteMatch{}) {
+ methods, err := route.GetMethods()
+ if err != nil {
+ return err
+ }
+
+ allMethods = append(allMethods, methods...)
+ }
+ break
+ }
+ }
+ return nil
+ })
+
+ return allMethods, err
+}
diff --git a/vendor/github.com/gorilla/mux/mux.go b/vendor/github.com/gorilla/mux/mux.go
index fb69196..a2cd193 100644
--- a/vendor/github.com/gorilla/mux/mux.go
+++ b/vendor/github.com/gorilla/mux/mux.go
@@ -10,16 +10,19 @@ import (
"net/http"
"path"
"regexp"
- "strings"
)
var (
+ // ErrMethodMismatch is returned when the method in the request does not match
+ // the method defined against the route.
ErrMethodMismatch = errors.New("method is not allowed")
+ // ErrNotFound is returned when no route match is found.
+ ErrNotFound = errors.New("no matching route was found")
)
// NewRouter returns a new router instance.
func NewRouter() *Router {
- return &Router{namedRoutes: make(map[string]*Route), KeepContext: false}
+ return &Router{namedRoutes: make(map[string]*Route)}
}
// Router registers routes to be matched and dispatches a handler.
@@ -47,42 +50,121 @@ type Router struct {
// Configurable Handler to be used when the request method does not match the route.
MethodNotAllowedHandler http.Handler
- // Parent route, if this is a subrouter.
- parent parentRoute
// Routes to be matched, in order.
routes []*Route
+
// Routes by name for URL building.
namedRoutes map[string]*Route
- // See Router.StrictSlash(). This defines the flag for new routes.
- strictSlash bool
- // See Router.SkipClean(). This defines the flag for new routes.
- skipClean bool
+
// If true, do not clear the request context after handling the request.
- // This has no effect when go1.7+ is used, since the context is stored
+ //
+ // Deprecated: No effect when go1.7+ is used, since the context is stored
// on the request itself.
KeepContext bool
- // see Router.UseEncodedPath(). This defines a flag for all routes.
- useEncodedPath bool
+
+ // Slice of middlewares to be called after a match is found
+ middlewares []middleware
+
+ // configuration shared with `Route`
+ routeConf
}
-// Match matches registered routes against the request.
+// common route configuration shared between `Router` and `Route`
+type routeConf struct {
+ // If true, "/path/foo%2Fbar/to" will match the path "/path/{var}/to"
+ useEncodedPath bool
+
+ // If true, when the path pattern is "/path/", accessing "/path" will
+ // redirect to the former and vice versa.
+ strictSlash bool
+
+ // If true, when the path pattern is "/path//to", accessing "/path//to"
+ // will not redirect
+ skipClean bool
+
+ // Manager for the variables from host and path.
+ regexp routeRegexpGroup
+
+ // List of matchers.
+ matchers []matcher
+
+ // The scheme used when building URLs.
+ buildScheme string
+
+ buildVarsFunc BuildVarsFunc
+}
+
+// returns an effective deep copy of `routeConf`
+func copyRouteConf(r routeConf) routeConf {
+ c := r
+
+ if r.regexp.path != nil {
+ c.regexp.path = copyRouteRegexp(r.regexp.path)
+ }
+
+ if r.regexp.host != nil {
+ c.regexp.host = copyRouteRegexp(r.regexp.host)
+ }
+
+ c.regexp.queries = make([]*routeRegexp, 0, len(r.regexp.queries))
+ for _, q := range r.regexp.queries {
+ c.regexp.queries = append(c.regexp.queries, copyRouteRegexp(q))
+ }
+
+ c.matchers = make([]matcher, 0, len(r.matchers))
+ for _, m := range r.matchers {
+ c.matchers = append(c.matchers, m)
+ }
+
+ return c
+}
+
+func copyRouteRegexp(r *routeRegexp) *routeRegexp {
+ c := *r
+ return &c
+}
+
+// Match attempts to match the given request against the router's registered routes.
+//
+// If the request matches a route of this router or one of its subrouters the Route,
+// Handler, and Vars fields of the the match argument are filled and this function
+// returns true.
+//
+// If the request does not match any of this router's or its subrouters' routes
+// then this function returns false. If available, a reason for the match failure
+// will be filled in the match argument's MatchErr field. If the match failure type
+// (eg: not found) has a registered handler, the handler is assigned to the Handler
+// field of the match argument.
func (r *Router) Match(req *http.Request, match *RouteMatch) bool {
for _, route := range r.routes {
if route.Match(req, match) {
+ // Build middleware chain if no error was found
+ if match.MatchErr == nil {
+ for i := len(r.middlewares) - 1; i >= 0; i-- {
+ match.Handler = r.middlewares[i].Middleware(match.Handler)
+ }
+ }
return true
}
}
- if match.MatchErr == ErrMethodMismatch && r.MethodNotAllowedHandler != nil {
- match.Handler = r.MethodNotAllowedHandler
- return true
+ if match.MatchErr == ErrMethodMismatch {
+ if r.MethodNotAllowedHandler != nil {
+ match.Handler = r.MethodNotAllowedHandler
+ return true
+ }
+
+ return false
}
// Closest match for a router (includes sub-routers)
if r.NotFoundHandler != nil {
match.Handler = r.NotFoundHandler
+ match.MatchErr = ErrNotFound
return true
}
+
+ match.MatchErr = ErrNotFound
return false
}
@@ -94,7 +176,7 @@ func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
if !r.skipClean {
path := req.URL.Path
if r.useEncodedPath {
- path = getPath(req)
+ path = req.URL.EscapedPath()
}
// Clean path to canonical form and redirect.
if p := cleanPath(path); p != path {
@@ -127,33 +209,35 @@ func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
handler = http.NotFoundHandler()
}
- if !r.KeepContext {
- defer contextClear(req)
- }
handler.ServeHTTP(w, req)
}
// Get returns a route registered with the given name.
func (r *Router) Get(name string) *Route {
- return r.getNamedRoutes()[name]
+ return r.namedRoutes[name]
}
// GetRoute returns a route registered with the given name. This method
// was renamed to Get() and remains here for backwards compatibility.
func (r *Router) GetRoute(name string) *Route {
- return r.getNamedRoutes()[name]
+ return r.namedRoutes[name]
}
// StrictSlash defines the trailing slash behavior for new routes. The initial
// value is false.
//
-// When true, if the route path is "/path/", accessing "/path" will redirect
+// When true, if the route path is "/path/", accessing "/path" will perform a redirect
// to the former and vice versa. In other words, your application will always
// see the path as specified in the route.
//
// When false, if the route path is "/path", accessing "/path/" will not match
// this route and vice versa.
//
+// The re-direct is a HTTP 301 (Moved Permanently). Note that when this is set for
+// routes with a non-idempotent method (e.g. POST, PUT), the subsequent re-directed
+// request will be made as a GET by most clients. Use middleware or client settings
+// to modify this behaviour as needed.
+//
// Special case: when a route sets a path prefix using the PathPrefix() method,
// strict slash is ignored for that route because the redirect behavior can't
// be determined from a prefix alone. However, any subrouters created from that
@@ -179,10 +263,6 @@ func (r *Router) SkipClean(value bool) *Router {
// UseEncodedPath tells the router to match the encoded original path
// to the routes.
// For eg. "/path/foo%2Fbar/to" will match the path "/path/{var}/to".
-// This behavior has the drawback of needing to match routes against
-// r.RequestURI instead of r.URL.Path. Any modifications (such as http.StripPrefix)
-// to r.URL.Path will not affect routing when this flag is on and thus may
-// induce unintended behavior.
//
// If not called, the router will match the unencoded path to the routes.
// For eg. "/path/foo%2Fbar/to" will match the path "/path/foo/bar/to"
@@ -191,55 +271,24 @@ func (r *Router) UseEncodedPath() *Router {
return r
}
-// ----------------------------------------------------------------------------
-// parentRoute
-// ----------------------------------------------------------------------------
-
-func (r *Router) getBuildScheme() string {
- if r.parent != nil {
- return r.parent.getBuildScheme()
- }
- return ""
-}
-
-// getNamedRoutes returns the map where named routes are registered.
-func (r *Router) getNamedRoutes() map[string]*Route {
- if r.namedRoutes == nil {
- if r.parent != nil {
- r.namedRoutes = r.parent.getNamedRoutes()
- } else {
- r.namedRoutes = make(map[string]*Route)
- }
- }
- return r.namedRoutes
-}
-
-// getRegexpGroup returns regexp definitions from the parent route, if any.
-func (r *Router) getRegexpGroup() *routeRegexpGroup {
- if r.parent != nil {
- return r.parent.getRegexpGroup()
- }
- return nil
-}
-
-func (r *Router) buildVars(m map[string]string) map[string]string {
- if r.parent != nil {
- m = r.parent.buildVars(m)
- }
- return m
-}
-
// ----------------------------------------------------------------------------
// Route factories
// ----------------------------------------------------------------------------
// NewRoute registers an empty route.
func (r *Router) NewRoute() *Route {
- route := &Route{parent: r, strictSlash: r.strictSlash, skipClean: r.skipClean, useEncodedPath: r.useEncodedPath}
+ // initialize a route with a copy of the parent router's configuration
+ route := &Route{routeConf: copyRouteConf(r.routeConf), namedRoutes: r.namedRoutes}
r.routes = append(r.routes, route)
return route
}
+// Name registers a new route with a name.
+// See Route.Name().
+func (r *Router) Name(name string) *Route {
+ return r.NewRoute().Name(name)
+}
+
// Handle registers a new route with a matcher for the URL path.
// See Route.Path() and Route.Handler().
func (r *Router) Handle(path string, handler http.Handler) *Route {
@@ -409,28 +458,6 @@ func setCurrentRoute(r *http.Request, val interface{}) *http.Request {
// Helpers
// ----------------------------------------------------------------------------
-// getPath returns the escaped path if possible; doing what URL.EscapedPath()
-// which was added in go1.5 does
-func getPath(req *http.Request) string {
- if req.RequestURI != "" {
- // Extract the path from RequestURI (which is escaped unlike URL.Path)
- // as detailed here as detailed in https://golang.org/pkg/net/url/#URL
- // for < 1.5 server side workaround
- // http://localhost/path/here?v=1 -> /path/here
- path := req.RequestURI
- path = strings.TrimPrefix(path, req.URL.Scheme+`://`)
- path = strings.TrimPrefix(path, req.URL.Host)
- if i := strings.LastIndex(path, "?"); i > -1 {
- path = path[:i]
- }
- if i := strings.LastIndex(path, "#"); i > -1 {
- path = path[:i]
- }
- return path
- }
- return req.URL.Path
-}
-
// cleanPath returns the canonical path for p, eliminating . and .. elements.
// Borrowed from the net/http package.
func cleanPath(p string) string {
diff --git a/vendor/github.com/gorilla/mux/regexp.go b/vendor/github.com/gorilla/mux/regexp.go
index 80d1f78..ac1abcd 100644
--- a/vendor/github.com/gorilla/mux/regexp.go
+++ b/vendor/github.com/gorilla/mux/regexp.go
@@ -14,6 +14,20 @@ import (
"strings"
)
+type routeRegexpOptions struct {
+ strictSlash bool
+ useEncodedPath bool
+}
+
+type regexpType int
+
+const (
+ regexpTypePath regexpType = 0
+ regexpTypeHost regexpType = 1
+ regexpTypePrefix regexpType = 2
+ regexpTypeQuery regexpType = 3
+)
+
// newRouteRegexp parses a route template and returns a routeRegexp,
// used to match a host, a path or a query string.
//
@@ -24,7 +38,7 @@ import (
// Previously we accepted only Python-like identifiers for variable
// names ([a-zA-Z_][a-zA-Z0-9_]*), but currently the only restriction is that
// name and pattern can't be empty, and names can't contain a colon.
-func newRouteRegexp(tpl string, matchHost, matchPrefix, matchQuery, strictSlash, useEncodedPath bool) (*routeRegexp, error) {
+func newRouteRegexp(tpl string, typ regexpType, options routeRegexpOptions) (*routeRegexp, error) {
// Check if it is well-formed.
idxs, errBraces := braceIndices(tpl)
if errBraces != nil {
@@ -34,19 +48,18 @@ func newRouteRegexp(tpl string, matchHost, matchPrefix, matchQuery, strictSlash,
template := tpl
// Now let's parse it.
defaultPattern := "[^/]+"
- if matchQuery {
+ if typ == regexpTypeQuery {
defaultPattern = ".*"
- } else if matchHost {
+ } else if typ == regexpTypeHost {
defaultPattern = "[^.]+"
- matchPrefix = false
}
// Only match strict slash if not matching
- if matchPrefix || matchHost || matchQuery {
- strictSlash = false
+ if typ != regexpTypePath {
+ options.strictSlash = false
}
// Set a flag for strictSlash.
endSlash := false
- if strictSlash && strings.HasSuffix(tpl, "/") {
+ if options.strictSlash && strings.HasSuffix(tpl, "/") {
tpl = tpl[:len(tpl)-1]
endSlash = true
}
@@ -88,18 +101,25 @@ func newRouteRegexp(tpl string, matchHost, matchPrefix, matchQuery, strictSlash,
// Add the remaining.
raw := tpl[end:]
pattern.WriteString(regexp.QuoteMeta(raw))
- if strictSlash {
+ if options.strictSlash {
pattern.WriteString("[/]?")
}
- if matchQuery {
+ if typ == regexpTypeQuery {
// Add the default pattern if the query value is empty
if queryVal := strings.SplitN(template, "=", 2)[1]; queryVal == "" {
pattern.WriteString(defaultPattern)
}
}
- if !matchPrefix {
+ if typ != regexpTypePrefix {
pattern.WriteByte('$')
}
+
+ var wildcardHostPort bool
+ if typ == regexpTypeHost {
+ if !strings.Contains(pattern.String(), ":") {
+ wildcardHostPort = true
+ }
+ }
reverse.WriteString(raw)
if endSlash {
reverse.WriteByte('/')
@@ -118,15 +138,14 @@ func newRouteRegexp(tpl string, matchHost, matchPrefix, matchQuery, strictSlash,
// Done!
return &routeRegexp{
- template: template,
- matchHost: matchHost,
- matchQuery: matchQuery,
- strictSlash: strictSlash,
- useEncodedPath: useEncodedPath,
- regexp: reg,
- reverse: reverse.String(),
- varsN: varsN,
- varsR: varsR,
+ template: template,
+ regexpType: typ,
+ options: options,
+ regexp: reg,
+ reverse: reverse.String(),
+ varsN: varsN,
+ varsR: varsR,
+ wildcardHostPort: wildcardHostPort,
}, nil
}
@@ -135,15 +154,10 @@ func newRouteRegexp(tpl string, matchHost, matchPrefix, matchQuery, strictSlash,
type routeRegexp struct {
// The unmodified template.
template string
- // True for host match, false for path or query string match.
- matchHost bool
- // True for query string match, false for path and host match.
- matchQuery bool
- // The strictSlash value defined on the route, but disabled if PathPrefix was used.
- strictSlash bool
- // Determines whether to use encoded path from getPath function or unencoded
- // req.URL.Path for path matching
- useEncodedPath bool
+ // The type of match
+ regexpType regexpType
+ // Options for matching
+ options routeRegexpOptions
// Expanded regexp.
regexp *regexp.Regexp
// Reverse template.
@@ -152,22 +166,31 @@ type routeRegexp struct {
varsN []string
// Variable regexps (validators).
varsR []*regexp.Regexp
+ // Wildcard host-port (no strict port match in hostname)
+ wildcardHostPort bool
}
// Match matches the regexp against the URL host or path.
func (r *routeRegexp) Match(req *http.Request, match *RouteMatch) bool {
- if !r.matchHost {
- if r.matchQuery {
+ if r.regexpType == regexpTypeHost {
+ host := getHost(req)
+ if r.wildcardHostPort {
+ // Don't be strict on the port match
+ if i := strings.Index(host, ":"); i != -1 {
+ host = host[:i]
+ }
+ }
+ return r.regexp.MatchString(host)
+ } else {
+ if r.regexpType == regexpTypeQuery {
return r.matchQueryString(req)
}
path := req.URL.Path
- if r.useEncodedPath {
- path = getPath(req)
+ if r.options.useEncodedPath {
+ path = req.URL.EscapedPath()
}
return r.regexp.MatchString(path)
}
-
- return r.regexp.MatchString(getHost(req))
}
// url builds a URL part using the given values.
@@ -178,7 +201,7 @@ func (r *routeRegexp) url(values map[string]string) (string, error) {
if !ok {
return "", fmt.Errorf("mux: missing route variable %q", v)
}
- if r.matchQuery {
+ if r.regexpType == regexpTypeQuery {
value = url.QueryEscape(value)
}
urlValues[k] = value
@@ -203,7 +226,7 @@ func (r *routeRegexp) url(values map[string]string) (string, error) {
// For a URL with foo=bar&baz=ding, we return only the relevant key
// value pair for the routeRegexp.
func (r *routeRegexp) getURLQuery(req *http.Request) string {
- if !r.matchQuery {
+ if r.regexpType != regexpTypeQuery {
return ""
}
templateKey := strings.SplitN(r.template, "=", 2)[0]
@@ -261,7 +284,7 @@ type routeRegexpGroup struct {
}
// setMatch extracts the variables from the URL once a route matches.
-func (v *routeRegexpGroup) setMatch(req *http.Request, m *RouteMatch, r *Route) {
+func (v routeRegexpGroup) setMatch(req *http.Request, m *RouteMatch, r *Route) {
// Store host variables.
if v.host != nil {
host := getHost(req)
@@ -272,7 +295,7 @@ func (v *routeRegexpGroup) setMatch(req *http.Request, m *RouteMatch, r *Route)
}
path := req.URL.Path
if r.useEncodedPath {
- path = getPath(req)
+ path = req.URL.EscapedPath()
}
// Store path variables.
if v.path != nil {
@@ -280,7 +303,7 @@ func (v *routeRegexpGroup) setMatch(req *http.Request, m *RouteMatch, r *Route)
if len(matches) > 0 {
extractVars(path, matches, v.path.varsN, m.Vars)
// Check if we should redirect.
- if v.path.strictSlash {
+ if v.path.options.strictSlash {
p1 := strings.HasSuffix(path, "/")
p2 := strings.HasSuffix(v.path.template, "/")
if p1 != p2 {
@@ -290,7 +313,7 @@ func (v *routeRegexpGroup) setMatch(req *http.Request, m *RouteMatch, r *Route)
} else {
u.Path += "/"
}
- m.Handler = http.RedirectHandler(u.String(), 301)
+ m.Handler = http.RedirectHandler(u.String(), http.StatusMovedPermanently)
}
}
}
@@ -306,17 +329,13 @@ func (v *routeRegexpGroup) setMatch(req *http.Request, m *RouteMatch, r *Route)
}
// getHost tries its best to return the request host.
+// According to section 14.23 of RFC 2616 the Host header
+// can include the port number if the default value of 80 is not used.
func getHost(r *http.Request) string {
if r.URL.IsAbs() {
return r.URL.Host
}
- host := r.Host
- // Slice off any port information.
- if i := strings.Index(host, ":"); i != -1 {
- host = host[:i]
- }
- return host
-
+ return r.Host
}
func extractVars(input string, matches []int, names []string, output map[string]string) {
diff --git a/vendor/github.com/gorilla/mux/route.go b/vendor/github.com/gorilla/mux/route.go
index 6863adb..8479c68 100644
--- a/vendor/github.com/gorilla/mux/route.go
+++ b/vendor/github.com/gorilla/mux/route.go
@@ -15,24 +15,8 @@ import (
// Route stores information to match a request and build URLs.
type Route struct {
- // Parent where the route was registered (a Router).
- parent parentRoute
// Request handler for the route.
handler http.Handler
- // List of matchers.
- matchers []matcher
- // Manager for the variables from host and path.
- regexp *routeRegexpGroup
- // If true, when the path pattern is "/path/", accessing "/path" will
- // redirect to the former and vice versa.
- strictSlash bool
- // If true, when the path pattern is "/path//to", accessing "/path//to"
- // will not redirect
- skipClean bool
- // If true, "/path/foo%2Fbar/to" will match the path "/path/{var}/to"
- useEncodedPath bool
- // The scheme used when building URLs.
- buildScheme string
// If true, this route never matches: it is only used to build URLs.
buildOnly bool
// The name used to build URLs.
@@ -40,9 +24,15 @@ type Route struct {
// Error resulted from building a route.
err error
- buildVarsFunc BuildVarsFunc
+ // "global" reference to all named routes
+ namedRoutes map[string]*Route
+
+ // config possibly passed in from `Router`
+ routeConf
}
+// SkipClean reports whether path cleaning is enabled for this route via
+// Router.SkipClean.
func (r *Route) SkipClean() bool {
return r.skipClean
}
@@ -62,6 +52,18 @@ func (r *Route) Match(req *http.Request, match *RouteMatch) bool {
matchErr = ErrMethodMismatch
continue
}
+
+ // Ignore ErrNotFound errors. These errors arise from match call
+ // to Subrouters.
+ //
+ // This prevents subsequent matching subrouters from failing to
+ // run middleware. If not ignored, the middleware would see a
+ // non-nil MatchErr and be skipped, even when there was a
+ // matching route.
+ if match.MatchErr == ErrNotFound {
+ match.MatchErr = nil
+ }
+
matchErr = nil
return false
}
@@ -72,7 +74,13 @@ func (r *Route) Match(req *http.Request, match *RouteMatch) bool {
return false
}
- match.MatchErr = nil
+ if match.MatchErr == ErrMethodMismatch {
+ // We found a route which matches request method, clear MatchErr
+ match.MatchErr = nil
+ // Then override the mis-matched handler
+ match.Handler = r.handler
+ }
+
// Yay, we have a match. Let's collect some info about it.
if match.Route == nil {
match.Route = r
@@ -85,9 +93,7 @@ func (r *Route) Match(req *http.Request, match *RouteMatch) bool {
}
// Set variables.
- if r.regexp != nil {
- r.regexp.setMatch(req, match, r)
- }
+ r.regexp.setMatch(req, match, r)
return true
}
@@ -129,7 +135,7 @@ func (r *Route) GetHandler() http.Handler {
// Name -----------------------------------------------------------------------
// Name sets the name for the route, used to build URLs.
-// If the name was registered already it will be overwritten.
+// It is an error to call Name more than once on a route.
func (r *Route) Name(name string) *Route {
if r.name != "" {
r.err = fmt.Errorf("mux: route already has name %q, can't set %q",
@@ -137,7 +143,7 @@ func (r *Route) Name(name string) *Route {
}
if r.err == nil {
r.name = name
- r.getNamedRoutes()[name] = r
+ r.namedRoutes[name] = r
}
return r
}
@@ -165,12 +171,11 @@ func (r *Route) addMatcher(m matcher) *Route {
}
// addRegexpMatcher adds a host or path matcher and builder to a route.
-func (r *Route) addRegexpMatcher(tpl string, matchHost, matchPrefix, matchQuery bool) error {
+func (r *Route) addRegexpMatcher(tpl string, typ regexpType) error {
if r.err != nil {
return r.err
}
- r.regexp = r.getRegexpGroup()
- if !matchHost && !matchQuery {
+ if typ == regexpTypePath || typ == regexpTypePrefix {
if len(tpl) > 0 && tpl[0] != '/' {
return fmt.Errorf("mux: path must start with a slash, got %q", tpl)
}
@@ -178,7 +183,10 @@ func (r *Route) addRegexpMatcher(tpl string, matchHost, matchPrefix, matchQuery
tpl = strings.TrimRight(r.regexp.path.template, "/") + tpl
}
}
- rr, err := newRouteRegexp(tpl, matchHost, matchPrefix, matchQuery, r.strictSlash, r.useEncodedPath)
+ rr, err := newRouteRegexp(tpl, typ, routeRegexpOptions{
+ strictSlash: r.strictSlash,
+ useEncodedPath: r.useEncodedPath,
+ })
if err != nil {
return err
}
@@ -187,7 +195,7 @@ func (r *Route) addRegexpMatcher(tpl string, matchHost, matchPrefix, matchQuery
return err
}
}
- if matchHost {
+ if typ == regexpTypeHost {
if r.regexp.path != nil {
if err = uniqueVars(rr.varsN, r.regexp.path.varsN); err != nil {
return err
@@ -200,7 +208,7 @@ func (r *Route) addRegexpMatcher(tpl string, matchHost, matchPrefix, matchQuery
return err
}
}
- if matchQuery {
+ if typ == regexpTypeQuery {
r.regexp.queries = append(r.regexp.queries, rr)
} else {
r.regexp.path = rr
@@ -252,7 +260,8 @@ func (m headerRegexMatcher) Match(r *http.Request, match *RouteMatch) bool {
// "X-Requested-With", "XMLHttpRequest")
//
// The above route will only match if both the request header matches both regular expressions.
-// It the value is an empty string, it will match any value if the key is set.
+// If the value is an empty string, it will match any value if the key is set.
+// Use the start and end of string anchors (^ and $) to match an exact value.
func (r *Route) HeadersRegexp(pairs ...string) *Route {
if r.err == nil {
var headers map[string]*regexp.Regexp
@@ -282,7 +291,7 @@ func (r *Route) HeadersRegexp(pairs ...string) *Route {
// Variable names must be unique in a given route. They can be retrieved
// calling mux.Vars(request).
func (r *Route) Host(tpl string) *Route {
- r.err = r.addRegexpMatcher(tpl, true, false, false)
+ r.err = r.addRegexpMatcher(tpl, regexpTypeHost)
return r
}
@@ -342,7 +351,7 @@ func (r *Route) Methods(methods ...string) *Route {
// Variable names must be unique in a given route. They can be retrieved
// calling mux.Vars(request).
func (r *Route) Path(tpl string) *Route {
- r.err = r.addRegexpMatcher(tpl, false, false, false)
+ r.err = r.addRegexpMatcher(tpl, regexpTypePath)
return r
}
@@ -358,7 +367,7 @@ func (r *Route) Path(tpl string) *Route {
// Also note that the setting of Router.StrictSlash() has no effect on routes
// with a PathPrefix matcher.
func (r *Route) PathPrefix(tpl string) *Route {
- r.err = r.addRegexpMatcher(tpl, false, true, false)
+ r.err = r.addRegexpMatcher(tpl, regexpTypePrefix)
return r
}
@@ -374,7 +383,7 @@ func (r *Route) PathPrefix(tpl string) *Route {
// The above route will only match if the URL contains the defined queries
// values, e.g.: ?foo=bar&id=42.
//
-// It the value is an empty string, it will match any value if the key is set.
+// If the value is an empty string, it will match any value if the key is set.
//
// Variables can define an optional regexp pattern to be matched:
//
@@ -389,7 +398,7 @@ func (r *Route) Queries(pairs ...string) *Route {
return nil
}
for i := 0; i < length; i += 2 {
- if r.err = r.addRegexpMatcher(pairs[i]+"="+pairs[i+1], false, false, true); r.err != nil {
+ if r.err = r.addRegexpMatcher(pairs[i]+"="+pairs[i+1], regexpTypeQuery); r.err != nil {
return r
}
}
@@ -412,7 +421,7 @@ func (r *Route) Schemes(schemes ...string) *Route {
for k, v := range schemes {
schemes[k] = strings.ToLower(v)
}
- if r.buildScheme == "" && len(schemes) > 0 {
+ if len(schemes) > 0 {
r.buildScheme = schemes[0]
}
return r.addMatcher(schemeMatcher(schemes))
@@ -427,7 +436,15 @@ type BuildVarsFunc func(map[string]string) map[string]string
// BuildVarsFunc adds a custom function to be used to modify build variables
// before a route's URL is built.
func (r *Route) BuildVarsFunc(f BuildVarsFunc) *Route {
- r.buildVarsFunc = f
+ if r.buildVarsFunc != nil {
+ // compose the old and new functions
+ old := r.buildVarsFunc
+ r.buildVarsFunc = func(m map[string]string) map[string]string {
+ return f(old(m))
+ }
+ } else {
+ r.buildVarsFunc = f
+ }
return r
}
@@ -446,7 +463,8 @@ func (r *Route) BuildVarsFunc(f BuildVarsFunc) *Route {
// Here, the routes registered in the subrouter won't be tested if the host
// doesn't match.
func (r *Route) Subrouter() *Router {
- router := &Router{parent: r, strictSlash: r.strictSlash}
+ // initialize a subrouter with a copy of the parent route's configuration
+ router := &Router{routeConf: copyRouteConf(r.routeConf), namedRoutes: r.namedRoutes}
r.addMatcher(router)
return router
}
@@ -490,9 +508,6 @@ func (r *Route) URL(pairs ...string) (*url.URL, error) {
if r.err != nil {
return nil, r.err
}
- if r.regexp == nil {
- return nil, errors.New("mux: route doesn't have a host or path")
- }
values, err := r.prepareVars(pairs...)
if err != nil {
return nil, err
@@ -504,8 +519,8 @@ func (r *Route) URL(pairs ...string) (*url.URL, error) {
return nil, err
}
scheme = "http"
- if s := r.getBuildScheme(); s != "" {
- scheme = s
+ if r.buildScheme != "" {
+ scheme = r.buildScheme
}
}
if r.regexp.path != nil {
@@ -535,7 +550,7 @@ func (r *Route) URLHost(pairs ...string) (*url.URL, error) {
if r.err != nil {
return nil, r.err
}
- if r.regexp == nil || r.regexp.host == nil {
+ if r.regexp.host == nil {
return nil, errors.New("mux: route doesn't have a host")
}
values, err := r.prepareVars(pairs...)
@@ -550,8 +565,8 @@ func (r *Route) URLHost(pairs ...string) (*url.URL, error) {
Scheme: "http",
Host: host,
}
- if s := r.getBuildScheme(); s != "" {
- u.Scheme = s
+ if r.buildScheme != "" {
+ u.Scheme = r.buildScheme
}
return u, nil
}
@@ -563,7 +578,7 @@ func (r *Route) URLPath(pairs ...string) (*url.URL, error) {
if r.err != nil {
return nil, r.err
}
- if r.regexp == nil || r.regexp.path == nil {
+ if r.regexp.path == nil {
return nil, errors.New("mux: route doesn't have a path")
}
values, err := r.prepareVars(pairs...)
@@ -588,7 +603,7 @@ func (r *Route) GetPathTemplate() (string, error) {
if r.err != nil {
return "", r.err
}
- if r.regexp == nil || r.regexp.path == nil {
+ if r.regexp.path == nil {
return "", errors.New("mux: route doesn't have a path")
}
return r.regexp.path.template, nil
@@ -602,16 +617,54 @@ func (r *Route) GetPathRegexp() (string, error) {
if r.err != nil {
return "", r.err
}
- if r.regexp == nil || r.regexp.path == nil {
+ if r.regexp.path == nil {
return "", errors.New("mux: route does not have a path")
}
return r.regexp.path.regexp.String(), nil
}
+// GetQueriesRegexp returns the expanded regular expressions used to match the
+// route queries.
+// This is useful for building simple REST API documentation and for instrumentation
+// against third-party services.
+// An error will be returned if the route does not have queries.
+func (r *Route) GetQueriesRegexp() ([]string, error) {
+ if r.err != nil {
+ return nil, r.err
+ }
+ if r.regexp.queries == nil {
+ return nil, errors.New("mux: route doesn't have queries")
+ }
+ var queries []string
+ for _, query := range r.regexp.queries {
+ queries = append(queries, query.regexp.String())
+ }
+ return queries, nil
+}
+
+// GetQueriesTemplates returns the templates used to build the
+// query matching.
+// This is useful for building simple REST API documentation and for instrumentation
+// against third-party services.
+// An error will be returned if the route does not define queries.
+func (r *Route) GetQueriesTemplates() ([]string, error) {
+ if r.err != nil {
+ return nil, r.err
+ }
+ if r.regexp.queries == nil {
+ return nil, errors.New("mux: route doesn't have queries")
+ }
+ var queries []string
+ for _, query := range r.regexp.queries {
+ queries = append(queries, query.template)
+ }
+ return queries, nil
+}
+
// GetMethods returns the methods the route matches against
// This is useful for building simple REST API documentation and for instrumentation
// against third-party services.
-// An empty list will be returned if route does not have methods.
+// An error will be returned if route does not have methods.
func (r *Route) GetMethods() ([]string, error) {
if r.err != nil {
return nil, r.err
@@ -621,7 +674,7 @@ func (r *Route) GetMethods() ([]string, error) {
return []string(methods), nil
}
}
- return nil, nil
+ return nil, errors.New("mux: route doesn't have methods")
}
// GetHostTemplate returns the template used to build the
@@ -633,7 +686,7 @@ func (r *Route) GetHostTemplate() (string, error) {
if r.err != nil {
return "", r.err
}
- if r.regexp == nil || r.regexp.host == nil {
+ if r.regexp.host == nil {
return "", errors.New("mux: route doesn't have a host")
}
return r.regexp.host.template, nil
@@ -650,64 +703,8 @@ func (r *Route) prepareVars(pairs ...string) (map[string]string, error) {
}
func (r *Route) buildVars(m map[string]string) map[string]string {
- if r.parent != nil {
- m = r.parent.buildVars(m)
- }
if r.buildVarsFunc != nil {
m = r.buildVarsFunc(m)
}
return m
}
-
-// ----------------------------------------------------------------------------
-// parentRoute
-// ----------------------------------------------------------------------------
-
-// parentRoute allows routes to know about parent host and path definitions.
-type parentRoute interface {
- getBuildScheme() string
- getNamedRoutes() map[string]*Route
- getRegexpGroup() *routeRegexpGroup
- buildVars(map[string]string) map[string]string
-}
-
-func (r *Route) getBuildScheme() string {
- if r.buildScheme != "" {
- return r.buildScheme
- }
- if r.parent != nil {
- return r.parent.getBuildScheme()
- }
- return ""
-}
-
-// getNamedRoutes returns the map where named routes are registered.
-func (r *Route) getNamedRoutes() map[string]*Route {
- if r.parent == nil {
- // During tests router is not always set.
- r.parent = NewRouter()
- }
- return r.parent.getNamedRoutes()
-}
-
-// getRegexpGroup returns regexp definitions from this route.
-func (r *Route) getRegexpGroup() *routeRegexpGroup {
- if r.regexp == nil {
- if r.parent == nil {
- // During tests router is not always set.
- r.parent = NewRouter()
- }
- regexp := r.parent.getRegexpGroup()
- if regexp == nil {
- r.regexp = new(routeRegexpGroup)
- } else {
- // Copy.
- r.regexp = &routeRegexpGroup{
- host: regexp.host,
- path: regexp.path,
- queries: regexp.queries,
- }
- }
- }
- return r.regexp
-}
diff --git a/vendor/github.com/gorilla/mux/test_helpers.go b/vendor/github.com/gorilla/mux/test_helpers.go
new file mode 100644
index 0000000..32ecffd
--- /dev/null
+++ b/vendor/github.com/gorilla/mux/test_helpers.go
@@ -0,0 +1,19 @@
+// Copyright 2012 The Gorilla 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 mux
+
+import "net/http"
+
+// SetURLVars sets the URL variables for the given request, to be accessed via
+// mux.Vars for testing route behaviour. Arguments are not modified, a shallow
+// copy is returned.
+//
+// This API should only be used for testing purposes; it provides a way to
+// inject variables into the request context. Alternatively, URL variables
+// can be set by making a route that captures the required variables,
+// starting a server and sending the request to that server.
+func SetURLVars(r *http.Request, val map[string]string) *http.Request {
+ return setVars(r, val)
+}
diff --git a/vendor/github.com/satori/go.uuid/.travis.yml b/vendor/github.com/satori/go.uuid/.travis.yml
deleted file mode 100644
index fdf960e..0000000
--- a/vendor/github.com/satori/go.uuid/.travis.yml
+++ /dev/null
@@ -1,22 +0,0 @@
-language: go
-sudo: false
-go:
- - 1.2
- - 1.3
- - 1.4
- - 1.5
- - 1.6
- - 1.7
- - 1.8
- - tip
-matrix:
- allow_failures:
- - go: tip
- fast_finish: true
-before_install:
- - go get github.com/mattn/goveralls
- - go get golang.org/x/tools/cmd/cover
-script:
- - $HOME/gopath/bin/goveralls -service=travis-ci
-notifications:
- email: false
diff --git a/vendor/github.com/satori/go.uuid/README.md b/vendor/github.com/satori/go.uuid/README.md
deleted file mode 100644
index b6aad1c..0000000
--- a/vendor/github.com/satori/go.uuid/README.md
+++ /dev/null
@@ -1,65 +0,0 @@
-# UUID package for Go language
-
-[](https://travis-ci.org/satori/go.uuid)
-[](https://coveralls.io/github/satori/go.uuid)
-[](http://godoc.org/github.com/satori/go.uuid)
-
-This package provides pure Go implementation of Universally Unique Identifier (UUID). Supported both creation and parsing of UUIDs.
-
-With 100% test coverage and benchmarks out of box.
-
-Supported versions:
-* Version 1, based on timestamp and MAC address (RFC 4122)
-* Version 2, based on timestamp, MAC address and POSIX UID/GID (DCE 1.1)
-* Version 3, based on MD5 hashing (RFC 4122)
-* Version 4, based on random numbers (RFC 4122)
-* Version 5, based on SHA-1 hashing (RFC 4122)
-
-## Installation
-
-Use the `go` command:
-
- $ go get github.com/satori/go.uuid
-
-## Requirements
-
-UUID package requires Go >= 1.2.
-
-## Example
-
-```go
-package main
-
-import (
- "fmt"
- "github.com/satori/go.uuid"
-)
-
-func main() {
- // Creating UUID Version 4
- u1 := uuid.NewV4()
- fmt.Printf("UUIDv4: %s\n", u1)
-
- // Parsing UUID from string input
- u2, err := uuid.FromString("6ba7b810-9dad-11d1-80b4-00c04fd430c8")
- if err != nil {
- fmt.Printf("Something gone wrong: %s", err)
- }
- fmt.Printf("Successfully parsed: %s", u2)
-}
-```
-
-## Documentation
-
-[Documentation](http://godoc.org/github.com/satori/go.uuid) is hosted at GoDoc project.
-
-## Links
-* [RFC 4122](http://tools.ietf.org/html/rfc4122)
-* [DCE 1.1: Authentication and Security Services](http://pubs.opengroup.org/onlinepubs/9696989899/chap5.htm#tagcjh_08_02_01_01)
-
-## Copyright
-
-Copyright (C) 2013-2016 by Maxim Bublis .
-
-UUID package released under MIT License.
-See [LICENSE](https://github.com/satori/go.uuid/blob/master/LICENSE) for details.
diff --git a/vendor/github.com/satori/go.uuid/uuid.go b/vendor/github.com/satori/go.uuid/uuid.go
deleted file mode 100644
index 295f3fc..0000000
--- a/vendor/github.com/satori/go.uuid/uuid.go
+++ /dev/null
@@ -1,481 +0,0 @@
-// Copyright (C) 2013-2015 by Maxim Bublis
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-// Package uuid provides implementation of Universally Unique Identifier (UUID).
-// Supported versions are 1, 3, 4 and 5 (as specified in RFC 4122) and
-// version 2 (as specified in DCE 1.1).
-package uuid
-
-import (
- "bytes"
- "crypto/md5"
- "crypto/rand"
- "crypto/sha1"
- "database/sql/driver"
- "encoding/binary"
- "encoding/hex"
- "fmt"
- "hash"
- "net"
- "os"
- "sync"
- "time"
-)
-
-// UUID layout variants.
-const (
- VariantNCS = iota
- VariantRFC4122
- VariantMicrosoft
- VariantFuture
-)
-
-// UUID DCE domains.
-const (
- DomainPerson = iota
- DomainGroup
- DomainOrg
-)
-
-// Difference in 100-nanosecond intervals between
-// UUID epoch (October 15, 1582) and Unix epoch (January 1, 1970).
-const epochStart = 122192928000000000
-
-// Used in string method conversion
-const dash byte = '-'
-
-// UUID v1/v2 storage.
-var (
- storageMutex sync.Mutex
- storageOnce sync.Once
- epochFunc = unixTimeFunc
- clockSequence uint16
- lastTime uint64
- hardwareAddr [6]byte
- posixUID = uint32(os.Getuid())
- posixGID = uint32(os.Getgid())
-)
-
-// String parse helpers.
-var (
- urnPrefix = []byte("urn:uuid:")
- byteGroups = []int{8, 4, 4, 4, 12}
-)
-
-func initClockSequence() {
- buf := make([]byte, 2)
- safeRandom(buf)
- clockSequence = binary.BigEndian.Uint16(buf)
-}
-
-func initHardwareAddr() {
- interfaces, err := net.Interfaces()
- if err == nil {
- for _, iface := range interfaces {
- if len(iface.HardwareAddr) >= 6 {
- copy(hardwareAddr[:], iface.HardwareAddr)
- return
- }
- }
- }
-
- // Initialize hardwareAddr randomly in case
- // of real network interfaces absence
- safeRandom(hardwareAddr[:])
-
- // Set multicast bit as recommended in RFC 4122
- hardwareAddr[0] |= 0x01
-}
-
-func initStorage() {
- initClockSequence()
- initHardwareAddr()
-}
-
-func safeRandom(dest []byte) {
- if _, err := rand.Read(dest); err != nil {
- panic(err)
- }
-}
-
-// Returns difference in 100-nanosecond intervals between
-// UUID epoch (October 15, 1582) and current time.
-// This is default epoch calculation function.
-func unixTimeFunc() uint64 {
- return epochStart + uint64(time.Now().UnixNano()/100)
-}
-
-// UUID representation compliant with specification
-// described in RFC 4122.
-type UUID [16]byte
-
-// NullUUID can be used with the standard sql package to represent a
-// UUID value that can be NULL in the database
-type NullUUID struct {
- UUID UUID
- Valid bool
-}
-
-// The nil UUID is special form of UUID that is specified to have all
-// 128 bits set to zero.
-var Nil = UUID{}
-
-// Predefined namespace UUIDs.
-var (
- NamespaceDNS, _ = FromString("6ba7b810-9dad-11d1-80b4-00c04fd430c8")
- NamespaceURL, _ = FromString("6ba7b811-9dad-11d1-80b4-00c04fd430c8")
- NamespaceOID, _ = FromString("6ba7b812-9dad-11d1-80b4-00c04fd430c8")
- NamespaceX500, _ = FromString("6ba7b814-9dad-11d1-80b4-00c04fd430c8")
-)
-
-// And returns result of binary AND of two UUIDs.
-func And(u1 UUID, u2 UUID) UUID {
- u := UUID{}
- for i := 0; i < 16; i++ {
- u[i] = u1[i] & u2[i]
- }
- return u
-}
-
-// Or returns result of binary OR of two UUIDs.
-func Or(u1 UUID, u2 UUID) UUID {
- u := UUID{}
- for i := 0; i < 16; i++ {
- u[i] = u1[i] | u2[i]
- }
- return u
-}
-
-// Equal returns true if u1 and u2 equals, otherwise returns false.
-func Equal(u1 UUID, u2 UUID) bool {
- return bytes.Equal(u1[:], u2[:])
-}
-
-// Version returns algorithm version used to generate UUID.
-func (u UUID) Version() uint {
- return uint(u[6] >> 4)
-}
-
-// Variant returns UUID layout variant.
-func (u UUID) Variant() uint {
- switch {
- case (u[8] & 0x80) == 0x00:
- return VariantNCS
- case (u[8]&0xc0)|0x80 == 0x80:
- return VariantRFC4122
- case (u[8]&0xe0)|0xc0 == 0xc0:
- return VariantMicrosoft
- }
- return VariantFuture
-}
-
-// Bytes returns bytes slice representation of UUID.
-func (u UUID) Bytes() []byte {
- return u[:]
-}
-
-// Returns canonical string representation of UUID:
-// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.
-func (u UUID) String() string {
- buf := make([]byte, 36)
-
- hex.Encode(buf[0:8], u[0:4])
- buf[8] = dash
- hex.Encode(buf[9:13], u[4:6])
- buf[13] = dash
- hex.Encode(buf[14:18], u[6:8])
- buf[18] = dash
- hex.Encode(buf[19:23], u[8:10])
- buf[23] = dash
- hex.Encode(buf[24:], u[10:])
-
- return string(buf)
-}
-
-// SetVersion sets version bits.
-func (u *UUID) SetVersion(v byte) {
- u[6] = (u[6] & 0x0f) | (v << 4)
-}
-
-// SetVariant sets variant bits as described in RFC 4122.
-func (u *UUID) SetVariant() {
- u[8] = (u[8] & 0xbf) | 0x80
-}
-
-// MarshalText implements the encoding.TextMarshaler interface.
-// The encoding is the same as returned by String.
-func (u UUID) MarshalText() (text []byte, err error) {
- text = []byte(u.String())
- return
-}
-
-// UnmarshalText implements the encoding.TextUnmarshaler interface.
-// Following formats are supported:
-// "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
-// "{6ba7b810-9dad-11d1-80b4-00c04fd430c8}",
-// "urn:uuid:6ba7b810-9dad-11d1-80b4-00c04fd430c8"
-func (u *UUID) UnmarshalText(text []byte) (err error) {
- if len(text) < 32 {
- err = fmt.Errorf("uuid: UUID string too short: %s", text)
- return
- }
-
- t := text[:]
- braced := false
-
- if bytes.Equal(t[:9], urnPrefix) {
- t = t[9:]
- } else if t[0] == '{' {
- braced = true
- t = t[1:]
- }
-
- b := u[:]
-
- for i, byteGroup := range byteGroups {
- if i > 0 {
- if t[0] != '-' {
- err = fmt.Errorf("uuid: invalid string format")
- return
- }
- t = t[1:]
- }
-
- if len(t) < byteGroup {
- err = fmt.Errorf("uuid: UUID string too short: %s", text)
- return
- }
-
- if i == 4 && len(t) > byteGroup &&
- ((braced && t[byteGroup] != '}') || len(t[byteGroup:]) > 1 || !braced) {
- err = fmt.Errorf("uuid: UUID string too long: %s", text)
- return
- }
-
- _, err = hex.Decode(b[:byteGroup/2], t[:byteGroup])
- if err != nil {
- return
- }
-
- t = t[byteGroup:]
- b = b[byteGroup/2:]
- }
-
- return
-}
-
-// MarshalBinary implements the encoding.BinaryMarshaler interface.
-func (u UUID) MarshalBinary() (data []byte, err error) {
- data = u.Bytes()
- return
-}
-
-// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface.
-// It will return error if the slice isn't 16 bytes long.
-func (u *UUID) UnmarshalBinary(data []byte) (err error) {
- if len(data) != 16 {
- err = fmt.Errorf("uuid: UUID must be exactly 16 bytes long, got %d bytes", len(data))
- return
- }
- copy(u[:], data)
-
- return
-}
-
-// Value implements the driver.Valuer interface.
-func (u UUID) Value() (driver.Value, error) {
- return u.String(), nil
-}
-
-// Scan implements the sql.Scanner interface.
-// A 16-byte slice is handled by UnmarshalBinary, while
-// a longer byte slice or a string is handled by UnmarshalText.
-func (u *UUID) Scan(src interface{}) error {
- switch src := src.(type) {
- case []byte:
- if len(src) == 16 {
- return u.UnmarshalBinary(src)
- }
- return u.UnmarshalText(src)
-
- case string:
- return u.UnmarshalText([]byte(src))
- }
-
- return fmt.Errorf("uuid: cannot convert %T to UUID", src)
-}
-
-// Value implements the driver.Valuer interface.
-func (u NullUUID) Value() (driver.Value, error) {
- if !u.Valid {
- return nil, nil
- }
- // Delegate to UUID Value function
- return u.UUID.Value()
-}
-
-// Scan implements the sql.Scanner interface.
-func (u *NullUUID) Scan(src interface{}) error {
- if src == nil {
- u.UUID, u.Valid = Nil, false
- return nil
- }
-
- // Delegate to UUID Scan function
- u.Valid = true
- return u.UUID.Scan(src)
-}
-
-// FromBytes returns UUID converted from raw byte slice input.
-// It will return error if the slice isn't 16 bytes long.
-func FromBytes(input []byte) (u UUID, err error) {
- err = u.UnmarshalBinary(input)
- return
-}
-
-// FromBytesOrNil returns UUID converted from raw byte slice input.
-// Same behavior as FromBytes, but returns a Nil UUID on error.
-func FromBytesOrNil(input []byte) UUID {
- uuid, err := FromBytes(input)
- if err != nil {
- return Nil
- }
- return uuid
-}
-
-// FromString returns UUID parsed from string input.
-// Input is expected in a form accepted by UnmarshalText.
-func FromString(input string) (u UUID, err error) {
- err = u.UnmarshalText([]byte(input))
- return
-}
-
-// FromStringOrNil returns UUID parsed from string input.
-// Same behavior as FromString, but returns a Nil UUID on error.
-func FromStringOrNil(input string) UUID {
- uuid, err := FromString(input)
- if err != nil {
- return Nil
- }
- return uuid
-}
-
-// Returns UUID v1/v2 storage state.
-// Returns epoch timestamp, clock sequence, and hardware address.
-func getStorage() (uint64, uint16, []byte) {
- storageOnce.Do(initStorage)
-
- storageMutex.Lock()
- defer storageMutex.Unlock()
-
- timeNow := epochFunc()
- // Clock changed backwards since last UUID generation.
- // Should increase clock sequence.
- if timeNow <= lastTime {
- clockSequence++
- }
- lastTime = timeNow
-
- return timeNow, clockSequence, hardwareAddr[:]
-}
-
-// NewV1 returns UUID based on current timestamp and MAC address.
-func NewV1() UUID {
- u := UUID{}
-
- timeNow, clockSeq, hardwareAddr := getStorage()
-
- binary.BigEndian.PutUint32(u[0:], uint32(timeNow))
- binary.BigEndian.PutUint16(u[4:], uint16(timeNow>>32))
- binary.BigEndian.PutUint16(u[6:], uint16(timeNow>>48))
- binary.BigEndian.PutUint16(u[8:], clockSeq)
-
- copy(u[10:], hardwareAddr)
-
- u.SetVersion(1)
- u.SetVariant()
-
- return u
-}
-
-// NewV2 returns DCE Security UUID based on POSIX UID/GID.
-func NewV2(domain byte) UUID {
- u := UUID{}
-
- timeNow, clockSeq, hardwareAddr := getStorage()
-
- switch domain {
- case DomainPerson:
- binary.BigEndian.PutUint32(u[0:], posixUID)
- case DomainGroup:
- binary.BigEndian.PutUint32(u[0:], posixGID)
- }
-
- binary.BigEndian.PutUint16(u[4:], uint16(timeNow>>32))
- binary.BigEndian.PutUint16(u[6:], uint16(timeNow>>48))
- binary.BigEndian.PutUint16(u[8:], clockSeq)
- u[9] = domain
-
- copy(u[10:], hardwareAddr)
-
- u.SetVersion(2)
- u.SetVariant()
-
- return u
-}
-
-// NewV3 returns UUID based on MD5 hash of namespace UUID and name.
-func NewV3(ns UUID, name string) UUID {
- u := newFromHash(md5.New(), ns, name)
- u.SetVersion(3)
- u.SetVariant()
-
- return u
-}
-
-// NewV4 returns random generated UUID.
-func NewV4() UUID {
- u := UUID{}
- safeRandom(u[:])
- u.SetVersion(4)
- u.SetVariant()
-
- return u
-}
-
-// NewV5 returns UUID based on SHA-1 hash of namespace UUID and name.
-func NewV5(ns UUID, name string) UUID {
- u := newFromHash(sha1.New(), ns, name)
- u.SetVersion(5)
- u.SetVariant()
-
- return u
-}
-
-// Returns UUID based on hashing of namespace UUID and name.
-func newFromHash(h hash.Hash, ns UUID, name string) UUID {
- u := UUID{}
- h.Write(ns[:])
- h.Write([]byte(name))
- copy(u[:], h.Sum(nil))
-
- return u
-}
diff --git a/vendor/golang.org/x/sys/unix/.gitignore b/vendor/golang.org/x/sys/unix/.gitignore
index e482715..e3e0fc6 100644
--- a/vendor/golang.org/x/sys/unix/.gitignore
+++ b/vendor/golang.org/x/sys/unix/.gitignore
@@ -1 +1,2 @@
_obj/
+unix.test
diff --git a/vendor/golang.org/x/sys/unix/README.md b/vendor/golang.org/x/sys/unix/README.md
index bc6f603..eb2f78a 100644
--- a/vendor/golang.org/x/sys/unix/README.md
+++ b/vendor/golang.org/x/sys/unix/README.md
@@ -14,7 +14,7 @@ migrating the build system to use containers so the builds are reproducible.
This is being done on an OS-by-OS basis. Please update this documentation as
components of the build system change.
-### Old Build System (currently for `GOOS != "Linux" || GOARCH == "sparc64"`)
+### Old Build System (currently for `GOOS != "linux"`)
The old build system generates the Go files based on the C header files
present on your system. This means that files
@@ -32,9 +32,9 @@ To build the files for your current OS and architecture, make sure GOOS and
GOARCH are set correctly and run `mkall.sh`. This will generate the files for
your specific system. Running `mkall.sh -n` shows the commands that will be run.
-Requirements: bash, perl, go
+Requirements: bash, go
-### New Build System (currently for `GOOS == "Linux" && GOARCH != "sparc64"`)
+### New Build System (currently for `GOOS == "linux"`)
The new build system uses a Docker container to generate the go files directly
from source checkouts of the kernel and various system libraries. This means
@@ -52,14 +52,14 @@ system and have your GOOS and GOARCH set accordingly. Running `mkall.sh` will
then generate all of the files for all of the GOOS/GOARCH pairs in the new build
system. Running `mkall.sh -n` shows the commands that will be run.
-Requirements: bash, perl, go, docker
+Requirements: bash, go, docker
## Component files
This section describes the various files used in the code generation process.
It also contains instructions on how to modify these files to add a new
architecture/OS or to add additional syscalls, types, or constants. Note that
-if you are using the new build system, the scripts cannot be called normally.
+if you are using the new build system, the scripts/programs cannot be called normally.
They must be called from within the docker container.
### asm files
@@ -81,8 +81,8 @@ each GOOS/GOARCH pair.
### mksysnum
-Mksysnum is a script located at `${GOOS}/mksysnum.pl` (or `mksysnum_${GOOS}.pl`
-for the old system). This script takes in a list of header files containing the
+Mksysnum is a Go program located at `${GOOS}/mksysnum.go` (or `mksysnum_${GOOS}.go`
+for the old system). This program takes in a list of header files containing the
syscall number declarations and parses them to produce the corresponding list of
Go numeric constants. See `zsysnum_${GOOS}_${GOARCH}.go` for the generated
constants.
@@ -92,14 +92,14 @@ new installation of the target OS (or updating the source checkouts for the
new build system). However, depending on the OS, you make need to update the
parsing in mksysnum.
-### mksyscall.pl
+### mksyscall.go
The `syscall.go`, `syscall_${GOOS}.go`, `syscall_${GOOS}_${GOARCH}.go` are
hand-written Go files which implement system calls (for unix, the specific OS,
or the specific OS/Architecture pair respectively) that need special handling
and list `//sys` comments giving prototypes for ones that can be generated.
-The mksyscall.pl script takes the `//sys` and `//sysnb` comments and converts
+The mksyscall.go program takes the `//sys` and `//sysnb` comments and converts
them into syscalls. This requires the name of the prototype in the comment to
match a syscall number in the `zsysnum_${GOOS}_${GOARCH}.go` file. The function
prototype can be exported (capitalized) or not.
@@ -160,7 +160,7 @@ signal numbers, and constants. Generated by `mkerrors.sh` (see above).
### `zsyscall_${GOOS}_${GOARCH}.go`
A file containing all the generated syscalls for a specific GOOS and GOARCH.
-Generated by `mksyscall.pl` (see above).
+Generated by `mksyscall.go` (see above).
### `zsysnum_${GOOS}_${GOARCH}.go`
diff --git a/vendor/golang.org/x/sys/unix/affinity_linux.go b/vendor/golang.org/x/sys/unix/affinity_linux.go
new file mode 100644
index 0000000..6e5c81a
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/affinity_linux.go
@@ -0,0 +1,86 @@
+// Copyright 2018 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.
+
+// CPU affinity functions
+
+package unix
+
+import (
+ "math/bits"
+ "unsafe"
+)
+
+const cpuSetSize = _CPU_SETSIZE / _NCPUBITS
+
+// CPUSet represents a CPU affinity mask.
+type CPUSet [cpuSetSize]cpuMask
+
+func schedAffinity(trap uintptr, pid int, set *CPUSet) error {
+ _, _, e := RawSyscall(trap, uintptr(pid), uintptr(unsafe.Sizeof(*set)), uintptr(unsafe.Pointer(set)))
+ if e != 0 {
+ return errnoErr(e)
+ }
+ return nil
+}
+
+// SchedGetaffinity gets the CPU affinity mask of the thread specified by pid.
+// If pid is 0 the calling thread is used.
+func SchedGetaffinity(pid int, set *CPUSet) error {
+ return schedAffinity(SYS_SCHED_GETAFFINITY, pid, set)
+}
+
+// SchedSetaffinity sets the CPU affinity mask of the thread specified by pid.
+// If pid is 0 the calling thread is used.
+func SchedSetaffinity(pid int, set *CPUSet) error {
+ return schedAffinity(SYS_SCHED_SETAFFINITY, pid, set)
+}
+
+// Zero clears the set s, so that it contains no CPUs.
+func (s *CPUSet) Zero() {
+ for i := range s {
+ s[i] = 0
+ }
+}
+
+func cpuBitsIndex(cpu int) int {
+ return cpu / _NCPUBITS
+}
+
+func cpuBitsMask(cpu int) cpuMask {
+ return cpuMask(1 << (uint(cpu) % _NCPUBITS))
+}
+
+// Set adds cpu to the set s.
+func (s *CPUSet) Set(cpu int) {
+ i := cpuBitsIndex(cpu)
+ if i < len(s) {
+ s[i] |= cpuBitsMask(cpu)
+ }
+}
+
+// Clear removes cpu from the set s.
+func (s *CPUSet) Clear(cpu int) {
+ i := cpuBitsIndex(cpu)
+ if i < len(s) {
+ s[i] &^= cpuBitsMask(cpu)
+ }
+}
+
+// IsSet reports whether cpu is in the set s.
+func (s *CPUSet) IsSet(cpu int) bool {
+ i := cpuBitsIndex(cpu)
+ if i < len(s) {
+ return s[i]&cpuBitsMask(cpu) != 0
+ }
+ return false
+}
+
+// Count returns the number of CPUs in the set s.
+func (s *CPUSet) Count() int {
+ c := 0
+ for _, b := range s {
+ c += bits.OnesCount64(uint64(b))
+ }
+ return c
+}
diff --git a/vendor/golang.org/x/sys/unix/aliases.go b/vendor/golang.org/x/sys/unix/aliases.go
new file mode 100644
index 0000000..951fce4
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/aliases.go
@@ -0,0 +1,14 @@
+// Copyright 2018 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 aix darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build go1.9
+
+package unix
+
+import "syscall"
+
+type Signal = syscall.Signal
+type Errno = syscall.Errno
+type SysProcAttr = syscall.SysProcAttr
diff --git a/vendor/golang.org/x/sys/unix/asm_aix_ppc64.s b/vendor/golang.org/x/sys/unix/asm_aix_ppc64.s
new file mode 100644
index 0000000..06f84b8
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/asm_aix_ppc64.s
@@ -0,0 +1,17 @@
+// Copyright 2018 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 !gccgo
+
+#include "textflag.h"
+
+//
+// System calls for ppc64, AIX are implemented in runtime/syscall_aix.go
+//
+
+TEXT ·syscall6(SB),NOSPLIT,$0-88
+ JMP syscall·syscall6(SB)
+
+TEXT ·rawSyscall6(SB),NOSPLIT,$0-88
+ JMP syscall·rawSyscall6(SB)
diff --git a/vendor/golang.org/x/sys/unix/asm_dragonfly_amd64.s b/vendor/golang.org/x/sys/unix/asm_dragonfly_amd64.s
index d5ed672..603dd57 100644
--- a/vendor/golang.org/x/sys/unix/asm_dragonfly_amd64.s
+++ b/vendor/golang.org/x/sys/unix/asm_dragonfly_amd64.s
@@ -13,17 +13,17 @@
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
-TEXT ·Syscall(SB),NOSPLIT,$0-64
+TEXT ·Syscall(SB),NOSPLIT,$0-56
JMP syscall·Syscall(SB)
-TEXT ·Syscall6(SB),NOSPLIT,$0-88
+TEXT ·Syscall6(SB),NOSPLIT,$0-80
JMP syscall·Syscall6(SB)
-TEXT ·Syscall9(SB),NOSPLIT,$0-112
+TEXT ·Syscall9(SB),NOSPLIT,$0-104
JMP syscall·Syscall9(SB)
-TEXT ·RawSyscall(SB),NOSPLIT,$0-64
+TEXT ·RawSyscall(SB),NOSPLIT,$0-56
JMP syscall·RawSyscall(SB)
-TEXT ·RawSyscall6(SB),NOSPLIT,$0-88
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
JMP syscall·RawSyscall6(SB)
diff --git a/vendor/golang.org/x/sys/unix/asm_freebsd_arm64.s b/vendor/golang.org/x/sys/unix/asm_freebsd_arm64.s
new file mode 100644
index 0000000..d9318cb
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/asm_freebsd_arm64.s
@@ -0,0 +1,29 @@
+// Copyright 2018 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 !gccgo
+
+#include "textflag.h"
+
+//
+// System call support for ARM64, FreeBSD
+//
+
+// Just jump to package syscall's implementation for all these functions.
+// The runtime may know about them.
+
+TEXT ·Syscall(SB),NOSPLIT,$0-56
+ JMP syscall·Syscall(SB)
+
+TEXT ·Syscall6(SB),NOSPLIT,$0-80
+ JMP syscall·Syscall6(SB)
+
+TEXT ·Syscall9(SB),NOSPLIT,$0-104
+ JMP syscall·Syscall9(SB)
+
+TEXT ·RawSyscall(SB),NOSPLIT,$0-56
+ JMP syscall·RawSyscall(SB)
+
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
+ JMP syscall·RawSyscall6(SB)
diff --git a/vendor/golang.org/x/sys/unix/asm_linux_386.s b/vendor/golang.org/x/sys/unix/asm_linux_386.s
index 4db2909..448bebb 100644
--- a/vendor/golang.org/x/sys/unix/asm_linux_386.s
+++ b/vendor/golang.org/x/sys/unix/asm_linux_386.s
@@ -10,21 +10,51 @@
// System calls for 386, Linux
//
+// See ../runtime/sys_linux_386.s for the reason why we always use int 0x80
+// instead of the glibc-specific "CALL 0x10(GS)".
+#define INVOKE_SYSCALL INT $0x80
+
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
-TEXT ·Syscall(SB),NOSPLIT,$0-28
+TEXT ·Syscall(SB),NOSPLIT,$0-28
JMP syscall·Syscall(SB)
-TEXT ·Syscall6(SB),NOSPLIT,$0-40
+TEXT ·Syscall6(SB),NOSPLIT,$0-40
JMP syscall·Syscall6(SB)
+TEXT ·SyscallNoError(SB),NOSPLIT,$0-24
+ CALL runtime·entersyscall(SB)
+ MOVL trap+0(FP), AX // syscall entry
+ MOVL a1+4(FP), BX
+ MOVL a2+8(FP), CX
+ MOVL a3+12(FP), DX
+ MOVL $0, SI
+ MOVL $0, DI
+ INVOKE_SYSCALL
+ MOVL AX, r1+16(FP)
+ MOVL DX, r2+20(FP)
+ CALL runtime·exitsyscall(SB)
+ RET
+
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
JMP syscall·RawSyscall(SB)
-TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
JMP syscall·RawSyscall6(SB)
+TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-24
+ MOVL trap+0(FP), AX // syscall entry
+ MOVL a1+4(FP), BX
+ MOVL a2+8(FP), CX
+ MOVL a3+12(FP), DX
+ MOVL $0, SI
+ MOVL $0, DI
+ INVOKE_SYSCALL
+ MOVL AX, r1+16(FP)
+ MOVL DX, r2+20(FP)
+ RET
+
TEXT ·socketcall(SB),NOSPLIT,$0-36
JMP syscall·socketcall(SB)
diff --git a/vendor/golang.org/x/sys/unix/asm_linux_amd64.s b/vendor/golang.org/x/sys/unix/asm_linux_amd64.s
index 44e25c6..c6468a9 100644
--- a/vendor/golang.org/x/sys/unix/asm_linux_amd64.s
+++ b/vendor/golang.org/x/sys/unix/asm_linux_amd64.s
@@ -13,17 +13,45 @@
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
-TEXT ·Syscall(SB),NOSPLIT,$0-56
+TEXT ·Syscall(SB),NOSPLIT,$0-56
JMP syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-80
JMP syscall·Syscall6(SB)
+TEXT ·SyscallNoError(SB),NOSPLIT,$0-48
+ CALL runtime·entersyscall(SB)
+ MOVQ a1+8(FP), DI
+ MOVQ a2+16(FP), SI
+ MOVQ a3+24(FP), DX
+ MOVQ $0, R10
+ MOVQ $0, R8
+ MOVQ $0, R9
+ MOVQ trap+0(FP), AX // syscall entry
+ SYSCALL
+ MOVQ AX, r1+32(FP)
+ MOVQ DX, r2+40(FP)
+ CALL runtime·exitsyscall(SB)
+ RET
+
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
JMP syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
JMP syscall·RawSyscall6(SB)
+TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48
+ MOVQ a1+8(FP), DI
+ MOVQ a2+16(FP), SI
+ MOVQ a3+24(FP), DX
+ MOVQ $0, R10
+ MOVQ $0, R8
+ MOVQ $0, R9
+ MOVQ trap+0(FP), AX // syscall entry
+ SYSCALL
+ MOVQ AX, r1+32(FP)
+ MOVQ DX, r2+40(FP)
+ RET
+
TEXT ·gettimeofday(SB),NOSPLIT,$0-16
JMP syscall·gettimeofday(SB)
diff --git a/vendor/golang.org/x/sys/unix/asm_linux_arm.s b/vendor/golang.org/x/sys/unix/asm_linux_arm.s
index cf0b574..cf0f357 100644
--- a/vendor/golang.org/x/sys/unix/asm_linux_arm.s
+++ b/vendor/golang.org/x/sys/unix/asm_linux_arm.s
@@ -13,17 +13,44 @@
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
-TEXT ·Syscall(SB),NOSPLIT,$0-28
+TEXT ·Syscall(SB),NOSPLIT,$0-28
B syscall·Syscall(SB)
-TEXT ·Syscall6(SB),NOSPLIT,$0-40
+TEXT ·Syscall6(SB),NOSPLIT,$0-40
B syscall·Syscall6(SB)
+TEXT ·SyscallNoError(SB),NOSPLIT,$0-24
+ BL runtime·entersyscall(SB)
+ MOVW trap+0(FP), R7
+ MOVW a1+4(FP), R0
+ MOVW a2+8(FP), R1
+ MOVW a3+12(FP), R2
+ MOVW $0, R3
+ MOVW $0, R4
+ MOVW $0, R5
+ SWI $0
+ MOVW R0, r1+16(FP)
+ MOVW $0, R0
+ MOVW R0, r2+20(FP)
+ BL runtime·exitsyscall(SB)
+ RET
+
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
B syscall·RawSyscall(SB)
-TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
B syscall·RawSyscall6(SB)
-TEXT ·seek(SB),NOSPLIT,$0-32
+TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-24
+ MOVW trap+0(FP), R7 // syscall entry
+ MOVW a1+4(FP), R0
+ MOVW a2+8(FP), R1
+ MOVW a3+12(FP), R2
+ SWI $0
+ MOVW R0, r1+16(FP)
+ MOVW $0, R0
+ MOVW R0, r2+20(FP)
+ RET
+
+TEXT ·seek(SB),NOSPLIT,$0-28
B syscall·seek(SB)
diff --git a/vendor/golang.org/x/sys/unix/asm_linux_arm64.s b/vendor/golang.org/x/sys/unix/asm_linux_arm64.s
index 4be9bfe..afe6fdf 100644
--- a/vendor/golang.org/x/sys/unix/asm_linux_arm64.s
+++ b/vendor/golang.org/x/sys/unix/asm_linux_arm64.s
@@ -11,14 +11,42 @@
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
-TEXT ·Syscall(SB),NOSPLIT,$0-56
+TEXT ·Syscall(SB),NOSPLIT,$0-56
B syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-80
B syscall·Syscall6(SB)
+TEXT ·SyscallNoError(SB),NOSPLIT,$0-48
+ BL runtime·entersyscall(SB)
+ MOVD a1+8(FP), R0
+ MOVD a2+16(FP), R1
+ MOVD a3+24(FP), R2
+ MOVD $0, R3
+ MOVD $0, R4
+ MOVD $0, R5
+ MOVD trap+0(FP), R8 // syscall entry
+ SVC
+ MOVD R0, r1+32(FP) // r1
+ MOVD R1, r2+40(FP) // r2
+ BL runtime·exitsyscall(SB)
+ RET
+
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
B syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
B syscall·RawSyscall6(SB)
+
+TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48
+ MOVD a1+8(FP), R0
+ MOVD a2+16(FP), R1
+ MOVD a3+24(FP), R2
+ MOVD $0, R3
+ MOVD $0, R4
+ MOVD $0, R5
+ MOVD trap+0(FP), R8 // syscall entry
+ SVC
+ MOVD R0, r1+32(FP)
+ MOVD R1, r2+40(FP)
+ RET
diff --git a/vendor/golang.org/x/sys/unix/asm_linux_mips64x.s b/vendor/golang.org/x/sys/unix/asm_linux_mips64x.s
index 724e580..ab9d638 100644
--- a/vendor/golang.org/x/sys/unix/asm_linux_mips64x.s
+++ b/vendor/golang.org/x/sys/unix/asm_linux_mips64x.s
@@ -15,14 +15,42 @@
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
-TEXT ·Syscall(SB),NOSPLIT,$0-56
+TEXT ·Syscall(SB),NOSPLIT,$0-56
JMP syscall·Syscall(SB)
-TEXT ·Syscall6(SB),NOSPLIT,$0-80
+TEXT ·Syscall6(SB),NOSPLIT,$0-80
JMP syscall·Syscall6(SB)
-TEXT ·RawSyscall(SB),NOSPLIT,$0-56
+TEXT ·SyscallNoError(SB),NOSPLIT,$0-48
+ JAL runtime·entersyscall(SB)
+ MOVV a1+8(FP), R4
+ MOVV a2+16(FP), R5
+ MOVV a3+24(FP), R6
+ MOVV R0, R7
+ MOVV R0, R8
+ MOVV R0, R9
+ MOVV trap+0(FP), R2 // syscall entry
+ SYSCALL
+ MOVV R2, r1+32(FP)
+ MOVV R3, r2+40(FP)
+ JAL runtime·exitsyscall(SB)
+ RET
+
+TEXT ·RawSyscall(SB),NOSPLIT,$0-56
JMP syscall·RawSyscall(SB)
-TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
JMP syscall·RawSyscall6(SB)
+
+TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48
+ MOVV a1+8(FP), R4
+ MOVV a2+16(FP), R5
+ MOVV a3+24(FP), R6
+ MOVV R0, R7
+ MOVV R0, R8
+ MOVV R0, R9
+ MOVV trap+0(FP), R2 // syscall entry
+ SYSCALL
+ MOVV R2, r1+32(FP)
+ MOVV R3, r2+40(FP)
+ RET
diff --git a/vendor/golang.org/x/sys/unix/asm_linux_mipsx.s b/vendor/golang.org/x/sys/unix/asm_linux_mipsx.s
index 2ea4257..99e5399 100644
--- a/vendor/golang.org/x/sys/unix/asm_linux_mipsx.s
+++ b/vendor/golang.org/x/sys/unix/asm_linux_mipsx.s
@@ -15,17 +15,40 @@
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
-TEXT ·Syscall(SB),NOSPLIT,$0-28
+TEXT ·Syscall(SB),NOSPLIT,$0-28
JMP syscall·Syscall(SB)
-TEXT ·Syscall6(SB),NOSPLIT,$0-40
+TEXT ·Syscall6(SB),NOSPLIT,$0-40
JMP syscall·Syscall6(SB)
-TEXT ·Syscall9(SB),NOSPLIT,$0-52
+TEXT ·Syscall9(SB),NOSPLIT,$0-52
JMP syscall·Syscall9(SB)
-TEXT ·RawSyscall(SB),NOSPLIT,$0-28
+TEXT ·SyscallNoError(SB),NOSPLIT,$0-24
+ JAL runtime·entersyscall(SB)
+ MOVW a1+4(FP), R4
+ MOVW a2+8(FP), R5
+ MOVW a3+12(FP), R6
+ MOVW R0, R7
+ MOVW trap+0(FP), R2 // syscall entry
+ SYSCALL
+ MOVW R2, r1+16(FP) // r1
+ MOVW R3, r2+20(FP) // r2
+ JAL runtime·exitsyscall(SB)
+ RET
+
+TEXT ·RawSyscall(SB),NOSPLIT,$0-28
JMP syscall·RawSyscall(SB)
-TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
JMP syscall·RawSyscall6(SB)
+
+TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-24
+ MOVW a1+4(FP), R4
+ MOVW a2+8(FP), R5
+ MOVW a3+12(FP), R6
+ MOVW trap+0(FP), R2 // syscall entry
+ SYSCALL
+ MOVW R2, r1+16(FP)
+ MOVW R3, r2+20(FP)
+ RET
diff --git a/vendor/golang.org/x/sys/unix/asm_linux_ppc64x.s b/vendor/golang.org/x/sys/unix/asm_linux_ppc64x.s
index 8d231fe..88f7125 100644
--- a/vendor/golang.org/x/sys/unix/asm_linux_ppc64x.s
+++ b/vendor/golang.org/x/sys/unix/asm_linux_ppc64x.s
@@ -15,14 +15,30 @@
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
-TEXT ·Syscall(SB),NOSPLIT,$0-56
- BR syscall·Syscall(SB)
+TEXT ·SyscallNoError(SB),NOSPLIT,$0-48
+ BL runtime·entersyscall(SB)
+ MOVD a1+8(FP), R3
+ MOVD a2+16(FP), R4
+ MOVD a3+24(FP), R5
+ MOVD R0, R6
+ MOVD R0, R7
+ MOVD R0, R8
+ MOVD trap+0(FP), R9 // syscall entry
+ SYSCALL R9
+ MOVD R3, r1+32(FP)
+ MOVD R4, r2+40(FP)
+ BL runtime·exitsyscall(SB)
+ RET
-TEXT ·Syscall6(SB),NOSPLIT,$0-80
- BR syscall·Syscall6(SB)
-
-TEXT ·RawSyscall(SB),NOSPLIT,$0-56
- BR syscall·RawSyscall(SB)
-
-TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
- BR syscall·RawSyscall6(SB)
+TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48
+ MOVD a1+8(FP), R3
+ MOVD a2+16(FP), R4
+ MOVD a3+24(FP), R5
+ MOVD R0, R6
+ MOVD R0, R7
+ MOVD R0, R8
+ MOVD trap+0(FP), R9 // syscall entry
+ SYSCALL R9
+ MOVD R3, r1+32(FP)
+ MOVD R4, r2+40(FP)
+ RET
diff --git a/vendor/golang.org/x/sys/unix/asm_linux_riscv64.s b/vendor/golang.org/x/sys/unix/asm_linux_riscv64.s
new file mode 100644
index 0000000..6db717d
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/asm_linux_riscv64.s
@@ -0,0 +1,54 @@
+// Copyright 2019 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 riscv64,!gccgo
+
+#include "textflag.h"
+
+//
+// System calls for linux/riscv64.
+//
+// Where available, just jump to package syscall's implementation of
+// these functions.
+
+TEXT ·Syscall(SB),NOSPLIT,$0-56
+ JMP syscall·Syscall(SB)
+
+TEXT ·Syscall6(SB),NOSPLIT,$0-80
+ JMP syscall·Syscall6(SB)
+
+TEXT ·SyscallNoError(SB),NOSPLIT,$0-48
+ CALL runtime·entersyscall(SB)
+ MOV a1+8(FP), A0
+ MOV a2+16(FP), A1
+ MOV a3+24(FP), A2
+ MOV $0, A3
+ MOV $0, A4
+ MOV $0, A5
+ MOV $0, A6
+ MOV trap+0(FP), A7 // syscall entry
+ ECALL
+ MOV A0, r1+32(FP) // r1
+ MOV A1, r2+40(FP) // r2
+ CALL runtime·exitsyscall(SB)
+ RET
+
+TEXT ·RawSyscall(SB),NOSPLIT,$0-56
+ JMP syscall·RawSyscall(SB)
+
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
+ JMP syscall·RawSyscall6(SB)
+
+TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48
+ MOV a1+8(FP), A0
+ MOV a2+16(FP), A1
+ MOV a3+24(FP), A2
+ MOV ZERO, A3
+ MOV ZERO, A4
+ MOV ZERO, A5
+ MOV trap+0(FP), A7 // syscall entry
+ ECALL
+ MOV A0, r1+32(FP)
+ MOV A1, r2+40(FP)
+ RET
diff --git a/vendor/golang.org/x/sys/unix/asm_linux_s390x.s b/vendor/golang.org/x/sys/unix/asm_linux_s390x.s
index 1188985..a5a863c 100644
--- a/vendor/golang.org/x/sys/unix/asm_linux_s390x.s
+++ b/vendor/golang.org/x/sys/unix/asm_linux_s390x.s
@@ -21,8 +21,36 @@ TEXT ·Syscall(SB),NOSPLIT,$0-56
TEXT ·Syscall6(SB),NOSPLIT,$0-80
BR syscall·Syscall6(SB)
+TEXT ·SyscallNoError(SB),NOSPLIT,$0-48
+ BL runtime·entersyscall(SB)
+ MOVD a1+8(FP), R2
+ MOVD a2+16(FP), R3
+ MOVD a3+24(FP), R4
+ MOVD $0, R5
+ MOVD $0, R6
+ MOVD $0, R7
+ MOVD trap+0(FP), R1 // syscall entry
+ SYSCALL
+ MOVD R2, r1+32(FP)
+ MOVD R3, r2+40(FP)
+ BL runtime·exitsyscall(SB)
+ RET
+
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
BR syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
BR syscall·RawSyscall6(SB)
+
+TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48
+ MOVD a1+8(FP), R2
+ MOVD a2+16(FP), R3
+ MOVD a3+24(FP), R4
+ MOVD $0, R5
+ MOVD $0, R6
+ MOVD $0, R7
+ MOVD trap+0(FP), R1 // syscall entry
+ SYSCALL
+ MOVD R2, r1+32(FP)
+ MOVD R3, r2+40(FP)
+ RET
diff --git a/vendor/golang.org/x/sys/unix/asm_netbsd_arm64.s b/vendor/golang.org/x/sys/unix/asm_netbsd_arm64.s
new file mode 100644
index 0000000..6f98ba5
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/asm_netbsd_arm64.s
@@ -0,0 +1,29 @@
+// Copyright 2019 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 !gccgo
+
+#include "textflag.h"
+
+//
+// System call support for ARM64, NetBSD
+//
+
+// Just jump to package syscall's implementation for all these functions.
+// The runtime may know about them.
+
+TEXT ·Syscall(SB),NOSPLIT,$0-56
+ B syscall·Syscall(SB)
+
+TEXT ·Syscall6(SB),NOSPLIT,$0-80
+ B syscall·Syscall6(SB)
+
+TEXT ·Syscall9(SB),NOSPLIT,$0-104
+ B syscall·Syscall9(SB)
+
+TEXT ·RawSyscall(SB),NOSPLIT,$0-56
+ B syscall·RawSyscall(SB)
+
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
+ B syscall·RawSyscall6(SB)
diff --git a/vendor/golang.org/x/sys/unix/asm_openbsd_arm64.s b/vendor/golang.org/x/sys/unix/asm_openbsd_arm64.s
new file mode 100644
index 0000000..0cedea3
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/asm_openbsd_arm64.s
@@ -0,0 +1,29 @@
+// Copyright 2019 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 !gccgo
+
+#include "textflag.h"
+
+//
+// System call support for arm64, OpenBSD
+//
+
+// Just jump to package syscall's implementation for all these functions.
+// The runtime may know about them.
+
+TEXT ·Syscall(SB),NOSPLIT,$0-56
+ JMP syscall·Syscall(SB)
+
+TEXT ·Syscall6(SB),NOSPLIT,$0-80
+ JMP syscall·Syscall6(SB)
+
+TEXT ·Syscall9(SB),NOSPLIT,$0-104
+ JMP syscall·Syscall9(SB)
+
+TEXT ·RawSyscall(SB),NOSPLIT,$0-56
+ JMP syscall·RawSyscall(SB)
+
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
+ JMP syscall·RawSyscall6(SB)
diff --git a/vendor/golang.org/x/sys/unix/bluetooth_linux.go b/vendor/golang.org/x/sys/unix/bluetooth_linux.go
index 6e32296..a178a61 100644
--- a/vendor/golang.org/x/sys/unix/bluetooth_linux.go
+++ b/vendor/golang.org/x/sys/unix/bluetooth_linux.go
@@ -23,6 +23,7 @@ const (
HCI_CHANNEL_USER = 1
HCI_CHANNEL_MONITOR = 2
HCI_CHANNEL_CONTROL = 3
+ HCI_CHANNEL_LOGGING = 4
)
// Socketoption Level
diff --git a/vendor/golang.org/x/sys/unix/cap_freebsd.go b/vendor/golang.org/x/sys/unix/cap_freebsd.go
index 83b6bce..df52048 100644
--- a/vendor/golang.org/x/sys/unix/cap_freebsd.go
+++ b/vendor/golang.org/x/sys/unix/cap_freebsd.go
@@ -7,7 +7,7 @@
package unix
import (
- errorspkg "errors"
+ "errors"
"fmt"
)
@@ -60,26 +60,26 @@ func CapRightsSet(rights *CapRights, setrights []uint64) error {
n := caparsize(rights)
if n < capArSizeMin || n > capArSizeMax {
- return errorspkg.New("bad rights size")
+ return errors.New("bad rights size")
}
for _, right := range setrights {
if caprver(right) != CAP_RIGHTS_VERSION_00 {
- return errorspkg.New("bad right version")
+ return errors.New("bad right version")
}
i, err := rightToIndex(right)
if err != nil {
return err
}
if i >= n {
- return errorspkg.New("index overflow")
+ return errors.New("index overflow")
}
if capidxbit(rights.Rights[i]) != capidxbit(right) {
- return errorspkg.New("index mismatch")
+ return errors.New("index mismatch")
}
rights.Rights[i] |= right
if capidxbit(rights.Rights[i]) != capidxbit(right) {
- return errorspkg.New("index mismatch (after assign)")
+ return errors.New("index mismatch (after assign)")
}
}
@@ -95,26 +95,26 @@ func CapRightsClear(rights *CapRights, clearrights []uint64) error {
n := caparsize(rights)
if n < capArSizeMin || n > capArSizeMax {
- return errorspkg.New("bad rights size")
+ return errors.New("bad rights size")
}
for _, right := range clearrights {
if caprver(right) != CAP_RIGHTS_VERSION_00 {
- return errorspkg.New("bad right version")
+ return errors.New("bad right version")
}
i, err := rightToIndex(right)
if err != nil {
return err
}
if i >= n {
- return errorspkg.New("index overflow")
+ return errors.New("index overflow")
}
if capidxbit(rights.Rights[i]) != capidxbit(right) {
- return errorspkg.New("index mismatch")
+ return errors.New("index mismatch")
}
rights.Rights[i] &= ^(right & 0x01FFFFFFFFFFFFFF)
if capidxbit(rights.Rights[i]) != capidxbit(right) {
- return errorspkg.New("index mismatch (after assign)")
+ return errors.New("index mismatch (after assign)")
}
}
@@ -130,22 +130,22 @@ func CapRightsIsSet(rights *CapRights, setrights []uint64) (bool, error) {
n := caparsize(rights)
if n < capArSizeMin || n > capArSizeMax {
- return false, errorspkg.New("bad rights size")
+ return false, errors.New("bad rights size")
}
for _, right := range setrights {
if caprver(right) != CAP_RIGHTS_VERSION_00 {
- return false, errorspkg.New("bad right version")
+ return false, errors.New("bad right version")
}
i, err := rightToIndex(right)
if err != nil {
return false, err
}
if i >= n {
- return false, errorspkg.New("index overflow")
+ return false, errors.New("index overflow")
}
if capidxbit(rights.Rights[i]) != capidxbit(right) {
- return false, errorspkg.New("index mismatch")
+ return false, errors.New("index mismatch")
}
if (rights.Rights[i] & right) != right {
return false, nil
diff --git a/vendor/golang.org/x/sys/unix/constants.go b/vendor/golang.org/x/sys/unix/constants.go
index a96f0eb..3a6ac64 100644
--- a/vendor/golang.org/x/sys/unix/constants.go
+++ b/vendor/golang.org/x/sys/unix/constants.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
package unix
diff --git a/vendor/golang.org/x/sys/unix/dev_aix_ppc.go b/vendor/golang.org/x/sys/unix/dev_aix_ppc.go
new file mode 100644
index 0000000..5e5fb45
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/dev_aix_ppc.go
@@ -0,0 +1,27 @@
+// Copyright 2018 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 aix
+// +build ppc
+
+// Functions to access/create device major and minor numbers matching the
+// encoding used by AIX.
+
+package unix
+
+// Major returns the major component of a Linux device number.
+func Major(dev uint64) uint32 {
+ return uint32((dev >> 16) & 0xffff)
+}
+
+// Minor returns the minor component of a Linux device number.
+func Minor(dev uint64) uint32 {
+ return uint32(dev & 0xffff)
+}
+
+// Mkdev returns a Linux device number generated from the given major and minor
+// components.
+func Mkdev(major, minor uint32) uint64 {
+ return uint64(((major) << 16) | (minor))
+}
diff --git a/vendor/golang.org/x/sys/unix/dev_aix_ppc64.go b/vendor/golang.org/x/sys/unix/dev_aix_ppc64.go
new file mode 100644
index 0000000..8b40124
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/dev_aix_ppc64.go
@@ -0,0 +1,29 @@
+// Copyright 2018 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 aix
+// +build ppc64
+
+// Functions to access/create device major and minor numbers matching the
+// encoding used AIX.
+
+package unix
+
+// Major returns the major component of a Linux device number.
+func Major(dev uint64) uint32 {
+ return uint32((dev & 0x3fffffff00000000) >> 32)
+}
+
+// Minor returns the minor component of a Linux device number.
+func Minor(dev uint64) uint32 {
+ return uint32((dev & 0x00000000ffffffff) >> 0)
+}
+
+// Mkdev returns a Linux device number generated from the given major and minor
+// components.
+func Mkdev(major, minor uint32) uint64 {
+ var DEVNO64 uint64
+ DEVNO64 = 0x8000000000000000
+ return ((uint64(major) << 32) | (uint64(minor) & 0x00000000FFFFFFFF) | DEVNO64)
+}
diff --git a/vendor/golang.org/x/sys/unix/dirent.go b/vendor/golang.org/x/sys/unix/dirent.go
index bd47581..304016b 100644
--- a/vendor/golang.org/x/sys/unix/dirent.go
+++ b/vendor/golang.org/x/sys/unix/dirent.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
+// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
package unix
diff --git a/vendor/golang.org/x/sys/unix/endian_little.go b/vendor/golang.org/x/sys/unix/endian_little.go
index 085df2d..bcdb5d3 100644
--- a/vendor/golang.org/x/sys/unix/endian_little.go
+++ b/vendor/golang.org/x/sys/unix/endian_little.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//
-// +build 386 amd64 amd64p32 arm arm64 ppc64le mipsle mips64le
+// +build 386 amd64 amd64p32 arm arm64 ppc64le mipsle mips64le riscv64
package unix
diff --git a/vendor/golang.org/x/sys/unix/env_unix.go b/vendor/golang.org/x/sys/unix/env_unix.go
index 45e281a..84178b0 100644
--- a/vendor/golang.org/x/sys/unix/env_unix.go
+++ b/vendor/golang.org/x/sys/unix/env_unix.go
@@ -1,8 +1,8 @@
-// Copyright 2010 The Go Authors. All rights reserved.
+// 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.
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
// Unix environment variables.
@@ -25,3 +25,7 @@ func Clearenv() {
func Environ() []string {
return syscall.Environ()
}
+
+func Unsetenv(key string) error {
+ return syscall.Unsetenv(key)
+}
diff --git a/vendor/golang.org/x/sys/unix/env_unset.go b/vendor/golang.org/x/sys/unix/env_unset.go
deleted file mode 100644
index 9222262..0000000
--- a/vendor/golang.org/x/sys/unix/env_unset.go
+++ /dev/null
@@ -1,14 +0,0 @@
-// 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.4
-
-package unix
-
-import "syscall"
-
-func Unsetenv(key string) error {
- // This was added in Go 1.4.
- return syscall.Unsetenv(key)
-}
diff --git a/vendor/golang.org/x/sys/unix/flock.go b/vendor/golang.org/x/sys/unix/fcntl.go
similarity index 54%
rename from vendor/golang.org/x/sys/unix/flock.go
rename to vendor/golang.org/x/sys/unix/fcntl.go
index 2994ce7..4dc5348 100644
--- a/vendor/golang.org/x/sys/unix/flock.go
+++ b/vendor/golang.org/x/sys/unix/fcntl.go
@@ -2,16 +2,30 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd
+// +build dragonfly freebsd linux netbsd openbsd
package unix
import "unsafe"
// fcntl64Syscall is usually SYS_FCNTL, but is overridden on 32-bit Linux
-// systems by flock_linux_32bit.go to be SYS_FCNTL64.
+// systems by fcntl_linux_32bit.go to be SYS_FCNTL64.
var fcntl64Syscall uintptr = SYS_FCNTL
+func fcntl(fd int, cmd, arg int) (int, error) {
+ valptr, _, errno := Syscall(fcntl64Syscall, uintptr(fd), uintptr(cmd), uintptr(arg))
+ var err error
+ if errno != 0 {
+ err = errno
+ }
+ return int(valptr), err
+}
+
+// FcntlInt performs a fcntl syscall on fd with the provided command and argument.
+func FcntlInt(fd uintptr, cmd, arg int) (int, error) {
+ return fcntl(int(fd), cmd, arg)
+}
+
// FcntlFlock performs a fcntl syscall for the F_GETLK, F_SETLK or F_SETLKW command.
func FcntlFlock(fd uintptr, cmd int, lk *Flock_t) error {
_, _, errno := Syscall(fcntl64Syscall, fd, uintptr(cmd), uintptr(unsafe.Pointer(lk)))
diff --git a/vendor/golang.org/x/sys/unix/fcntl_darwin.go b/vendor/golang.org/x/sys/unix/fcntl_darwin.go
new file mode 100644
index 0000000..5868a4a
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/fcntl_darwin.go
@@ -0,0 +1,18 @@
+// Copyright 2019 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 unix
+
+import "unsafe"
+
+// FcntlInt performs a fcntl syscall on fd with the provided command and argument.
+func FcntlInt(fd uintptr, cmd, arg int) (int, error) {
+ return fcntl(int(fd), cmd, arg)
+}
+
+// FcntlFlock performs a fcntl syscall for the F_GETLK, F_SETLK or F_SETLKW command.
+func FcntlFlock(fd uintptr, cmd int, lk *Flock_t) error {
+ _, err := fcntl(int(fd), cmd, int(uintptr(unsafe.Pointer(lk))))
+ return err
+}
diff --git a/vendor/golang.org/x/sys/unix/flock_linux_32bit.go b/vendor/golang.org/x/sys/unix/fcntl_linux_32bit.go
similarity index 100%
rename from vendor/golang.org/x/sys/unix/flock_linux_32bit.go
rename to vendor/golang.org/x/sys/unix/fcntl_linux_32bit.go
diff --git a/vendor/golang.org/x/sys/unix/fdset.go b/vendor/golang.org/x/sys/unix/fdset.go
new file mode 100644
index 0000000..b27be0a
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/fdset.go
@@ -0,0 +1,29 @@
+// Copyright 2019 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 aix darwin dragonfly freebsd linux netbsd openbsd solaris
+
+package unix
+
+// Set adds fd to the set fds.
+func (fds *FdSet) Set(fd int) {
+ fds.Bits[fd/NFDBITS] |= (1 << (uintptr(fd) % NFDBITS))
+}
+
+// Clear removes fd from the set fds.
+func (fds *FdSet) Clear(fd int) {
+ fds.Bits[fd/NFDBITS] &^= (1 << (uintptr(fd) % NFDBITS))
+}
+
+// IsSet returns whether fd is in the set fds.
+func (fds *FdSet) IsSet(fd int) bool {
+ return fds.Bits[fd/NFDBITS]&(1<<(uintptr(fd)%NFDBITS)) != 0
+}
+
+// Zero clears the set fds.
+func (fds *FdSet) Zero() {
+ for i := range fds.Bits {
+ fds.Bits[i] = 0
+ }
+}
diff --git a/vendor/golang.org/x/sys/unix/file_unix.go b/vendor/golang.org/x/sys/unix/file_unix.go
deleted file mode 100644
index 47f6a83..0000000
--- a/vendor/golang.org/x/sys/unix/file_unix.go
+++ /dev/null
@@ -1,27 +0,0 @@
-// 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 unix
-
-import (
- "os"
- "syscall"
-)
-
-// FIXME: unexported function from os
-// syscallMode returns the syscall-specific mode bits from Go's portable mode bits.
-func syscallMode(i os.FileMode) (o uint32) {
- o |= uint32(i.Perm())
- if i&os.ModeSetuid != 0 {
- o |= syscall.S_ISUID
- }
- if i&os.ModeSetgid != 0 {
- o |= syscall.S_ISGID
- }
- if i&os.ModeSticky != 0 {
- o |= syscall.S_ISVTX
- }
- // No mapping for Go's ModeTemporary (plan9 only).
- return
-}
diff --git a/vendor/golang.org/x/sys/unix/gccgo.go b/vendor/golang.org/x/sys/unix/gccgo.go
index 94c8232..cd6f5a6 100644
--- a/vendor/golang.org/x/sys/unix/gccgo.go
+++ b/vendor/golang.org/x/sys/unix/gccgo.go
@@ -1,19 +1,30 @@
-// Copyright 2015 The Go Authors. All rights reserved.
+// 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 gccgo
+// +build !aix
package unix
import "syscall"
-// We can't use the gc-syntax .s files for gccgo. On the plus side
+// We can't use the gc-syntax .s files for gccgo. On the plus side
// much of the functionality can be written directly in Go.
+//extern gccgoRealSyscallNoError
+func realSyscallNoError(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r uintptr)
+
//extern gccgoRealSyscall
func realSyscall(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r, errno uintptr)
+func SyscallNoError(trap, a1, a2, a3 uintptr) (r1, r2 uintptr) {
+ syscall.Entersyscall()
+ r := realSyscallNoError(trap, a1, a2, a3, 0, 0, 0, 0, 0, 0)
+ syscall.Exitsyscall()
+ return r, 0
+}
+
func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) {
syscall.Entersyscall()
r, errno := realSyscall(trap, a1, a2, a3, 0, 0, 0, 0, 0, 0)
@@ -35,6 +46,11 @@ func Syscall9(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr,
return r, 0, syscall.Errno(errno)
}
+func RawSyscallNoError(trap, a1, a2, a3 uintptr) (r1, r2 uintptr) {
+ r := realSyscallNoError(trap, a1, a2, a3, 0, 0, 0, 0, 0, 0)
+ return r, 0
+}
+
func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) {
r, errno := realSyscall(trap, a1, a2, a3, 0, 0, 0, 0, 0, 0)
return r, 0, syscall.Errno(errno)
diff --git a/vendor/golang.org/x/sys/unix/gccgo_c.c b/vendor/golang.org/x/sys/unix/gccgo_c.c
index 07f6be0..c44730c 100644
--- a/vendor/golang.org/x/sys/unix/gccgo_c.c
+++ b/vendor/golang.org/x/sys/unix/gccgo_c.c
@@ -1,8 +1,9 @@
-// Copyright 2015 The Go Authors. All rights reserved.
+// 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 gccgo
+// +build !aix
#include
#include
@@ -31,11 +32,8 @@ gccgoRealSyscall(uintptr_t trap, uintptr_t a1, uintptr_t a2, uintptr_t a3, uintp
return r;
}
-// Define the use function in C so that it is not inlined.
-
-extern void use(void *) __asm__ (GOSYM_PREFIX GOPKGPATH ".use") __attribute__((noinline));
-
-void
-use(void *p __attribute__ ((unused)))
+uintptr_t
+gccgoRealSyscallNoError(uintptr_t trap, uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5, uintptr_t a6, uintptr_t a7, uintptr_t a8, uintptr_t a9)
{
+ return syscall(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9);
}
diff --git a/vendor/golang.org/x/sys/unix/gccgo_linux_amd64.go b/vendor/golang.org/x/sys/unix/gccgo_linux_amd64.go
index bffe1a7..251a977 100644
--- a/vendor/golang.org/x/sys/unix/gccgo_linux_amd64.go
+++ b/vendor/golang.org/x/sys/unix/gccgo_linux_amd64.go
@@ -1,4 +1,4 @@
-// Copyright 2015 The Go Authors. All rights reserved.
+// 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.
diff --git a/vendor/golang.org/x/sys/unix/ioctl.go b/vendor/golang.org/x/sys/unix/ioctl.go
new file mode 100644
index 0000000..3559e5d
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/ioctl.go
@@ -0,0 +1,65 @@
+// Copyright 2018 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 aix darwin dragonfly freebsd linux netbsd openbsd solaris
+
+package unix
+
+import (
+ "runtime"
+ "unsafe"
+)
+
+// ioctl itself should not be exposed directly, but additional get/set
+// functions for specific types are permissible.
+
+// IoctlSetInt performs an ioctl operation which sets an integer value
+// on fd, using the specified request number.
+func IoctlSetInt(fd int, req uint, value int) error {
+ return ioctl(fd, req, uintptr(value))
+}
+
+// IoctlSetWinsize performs an ioctl on fd with a *Winsize argument.
+//
+// To change fd's window size, the req argument should be TIOCSWINSZ.
+func IoctlSetWinsize(fd int, req uint, value *Winsize) error {
+ // TODO: if we get the chance, remove the req parameter and
+ // hardcode TIOCSWINSZ.
+ err := ioctl(fd, req, uintptr(unsafe.Pointer(value)))
+ runtime.KeepAlive(value)
+ return err
+}
+
+// IoctlSetTermios performs an ioctl on fd with a *Termios.
+//
+// The req value will usually be TCSETA or TIOCSETA.
+func IoctlSetTermios(fd int, req uint, value *Termios) error {
+ // TODO: if we get the chance, remove the req parameter.
+ err := ioctl(fd, req, uintptr(unsafe.Pointer(value)))
+ runtime.KeepAlive(value)
+ return err
+}
+
+// IoctlGetInt performs an ioctl operation which gets an integer value
+// from fd, using the specified request number.
+//
+// A few ioctl requests use the return value as an output parameter;
+// for those, IoctlRetInt should be used instead of this function.
+func IoctlGetInt(fd int, req uint) (int, error) {
+ var value int
+ err := ioctl(fd, req, uintptr(unsafe.Pointer(&value)))
+ return value, err
+}
+
+func IoctlGetWinsize(fd int, req uint) (*Winsize, error) {
+ var value Winsize
+ err := ioctl(fd, req, uintptr(unsafe.Pointer(&value)))
+ return &value, err
+}
+
+func IoctlGetTermios(fd int, req uint) (*Termios, error) {
+ var value Termios
+ err := ioctl(fd, req, uintptr(unsafe.Pointer(&value)))
+ return &value, err
+}
diff --git a/vendor/golang.org/x/sys/unix/mkall.sh b/vendor/golang.org/x/sys/unix/mkall.sh
old mode 100755
new mode 100644
index 00b7ce7..fa0c69b
--- a/vendor/golang.org/x/sys/unix/mkall.sh
+++ b/vendor/golang.org/x/sys/unix/mkall.sh
@@ -10,13 +10,14 @@
GOOSARCH="${GOOS}_${GOARCH}"
# defaults
-mksyscall="./mksyscall.pl"
+mksyscall="go run mksyscall.go"
mkerrors="./mkerrors.sh"
zerrors="zerrors_$GOOSARCH.go"
mksysctl=""
zsysctl="zsysctl_$GOOSARCH.go"
mksysnum=
mktypes=
+mkasm=
run="sh"
cmd=""
@@ -45,11 +46,11 @@ case "$#" in
exit 2
esac
-if [[ "$GOOS" = "linux" ]] && [[ "$GOARCH" != "sparc64" ]]; then
- # Use then new build system
+if [[ "$GOOS" = "linux" ]]; then
+ # Use the Docker-based build system
# Files generated through docker (use $cmd so you can Ctl-C the build or run)
$cmd docker build --tag generate:$GOOS $GOOS
- $cmd docker run --interactive --tty --volume $(dirname "$(readlink -f "$0")"):/build generate:$GOOS
+ $cmd docker run --interactive --tty --volume $(cd -- "$(dirname -- "$0")" && /bin/pwd):/build generate:$GOOS
exit
fi
@@ -59,110 +60,132 @@ _* | *_ | _)
echo 'undefined $GOOS_$GOARCH:' "$GOOSARCH" 1>&2
exit 1
;;
+aix_ppc)
+ mkerrors="$mkerrors -maix32"
+ mksyscall="go run mksyscall_aix_ppc.go -aix"
+ mktypes="GOARCH=$GOARCH go tool cgo -godefs"
+ ;;
+aix_ppc64)
+ mkerrors="$mkerrors -maix64"
+ mksyscall="go run mksyscall_aix_ppc64.go -aix"
+ mktypes="GOARCH=$GOARCH go tool cgo -godefs"
+ ;;
darwin_386)
mkerrors="$mkerrors -m32"
- mksyscall="./mksyscall.pl -l32"
- mksysnum="./mksysnum_darwin.pl $(xcrun --show-sdk-path --sdk macosx)/usr/include/sys/syscall.h"
+ mksyscall="go run mksyscall.go -l32"
+ mksysnum="go run mksysnum.go $(xcrun --show-sdk-path --sdk macosx)/usr/include/sys/syscall.h"
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
+ mkasm="go run mkasm_darwin.go"
;;
darwin_amd64)
mkerrors="$mkerrors -m64"
- mksysnum="./mksysnum_darwin.pl $(xcrun --show-sdk-path --sdk macosx)/usr/include/sys/syscall.h"
+ mksysnum="go run mksysnum.go $(xcrun --show-sdk-path --sdk macosx)/usr/include/sys/syscall.h"
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
+ mkasm="go run mkasm_darwin.go"
;;
darwin_arm)
mkerrors="$mkerrors"
- mksysnum="./mksysnum_darwin.pl $(xcrun --show-sdk-path --sdk iphoneos)/usr/include/sys/syscall.h"
+ mksyscall="go run mksyscall.go -l32"
+ mksysnum="go run mksysnum.go $(xcrun --show-sdk-path --sdk iphoneos)/usr/include/sys/syscall.h"
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
+ mkasm="go run mkasm_darwin.go"
;;
darwin_arm64)
mkerrors="$mkerrors -m64"
- mksysnum="./mksysnum_darwin.pl $(xcrun --show-sdk-path --sdk iphoneos)/usr/include/sys/syscall.h"
- mktypes="GOARCH=$GOARCH go tool cgo -godefs"
- ;;
-dragonfly_386)
- mkerrors="$mkerrors -m32"
- mksyscall="./mksyscall.pl -l32 -dragonfly"
- mksysnum="curl -s 'http://gitweb.dragonflybsd.org/dragonfly.git/blob_plain/HEAD:/sys/kern/syscalls.master' | ./mksysnum_dragonfly.pl"
+ mksysnum="go run mksysnum.go $(xcrun --show-sdk-path --sdk iphoneos)/usr/include/sys/syscall.h"
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
+ mkasm="go run mkasm_darwin.go"
;;
dragonfly_amd64)
mkerrors="$mkerrors -m64"
- mksyscall="./mksyscall.pl -dragonfly"
- mksysnum="curl -s 'http://gitweb.dragonflybsd.org/dragonfly.git/blob_plain/HEAD:/sys/kern/syscalls.master' | ./mksysnum_dragonfly.pl"
+ mksyscall="go run mksyscall.go -dragonfly"
+ mksysnum="go run mksysnum.go 'https://gitweb.dragonflybsd.org/dragonfly.git/blob_plain/HEAD:/sys/kern/syscalls.master'"
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
;;
freebsd_386)
mkerrors="$mkerrors -m32"
- mksyscall="./mksyscall.pl -l32"
- mksysnum="curl -s 'http://svn.freebsd.org/base/stable/10/sys/kern/syscalls.master' | ./mksysnum_freebsd.pl"
+ mksyscall="go run mksyscall.go -l32"
+ mksysnum="go run mksysnum.go 'https://svn.freebsd.org/base/stable/11/sys/kern/syscalls.master'"
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
;;
freebsd_amd64)
mkerrors="$mkerrors -m64"
- mksysnum="curl -s 'http://svn.freebsd.org/base/stable/10/sys/kern/syscalls.master' | ./mksysnum_freebsd.pl"
+ mksysnum="go run mksysnum.go 'https://svn.freebsd.org/base/stable/11/sys/kern/syscalls.master'"
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
;;
freebsd_arm)
mkerrors="$mkerrors"
- mksyscall="./mksyscall.pl -l32 -arm"
- mksysnum="curl -s 'http://svn.freebsd.org/base/stable/10/sys/kern/syscalls.master' | ./mksysnum_freebsd.pl"
+ mksyscall="go run mksyscall.go -l32 -arm"
+ mksysnum="go run mksysnum.go 'https://svn.freebsd.org/base/stable/11/sys/kern/syscalls.master'"
# Let the type of C char be signed for making the bare syscall
# API consistent across platforms.
mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
;;
-linux_sparc64)
- GOOSARCH_in=syscall_linux_sparc64.go
- unistd_h=/usr/include/sparc64-linux-gnu/asm/unistd.h
+freebsd_arm64)
mkerrors="$mkerrors -m64"
- mksysnum="./mksysnum_linux.pl $unistd_h"
+ mksysnum="go run mksysnum.go 'https://svn.freebsd.org/base/stable/11/sys/kern/syscalls.master'"
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
;;
netbsd_386)
mkerrors="$mkerrors -m32"
- mksyscall="./mksyscall.pl -l32 -netbsd"
- mksysnum="curl -s 'http://cvsweb.netbsd.org/bsdweb.cgi/~checkout~/src/sys/kern/syscalls.master' | ./mksysnum_netbsd.pl"
+ mksyscall="go run mksyscall.go -l32 -netbsd"
+ mksysnum="go run mksysnum.go 'http://cvsweb.netbsd.org/bsdweb.cgi/~checkout~/src/sys/kern/syscalls.master'"
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
;;
netbsd_amd64)
mkerrors="$mkerrors -m64"
- mksyscall="./mksyscall.pl -netbsd"
- mksysnum="curl -s 'http://cvsweb.netbsd.org/bsdweb.cgi/~checkout~/src/sys/kern/syscalls.master' | ./mksysnum_netbsd.pl"
+ mksyscall="go run mksyscall.go -netbsd"
+ mksysnum="go run mksysnum.go 'http://cvsweb.netbsd.org/bsdweb.cgi/~checkout~/src/sys/kern/syscalls.master'"
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
;;
netbsd_arm)
mkerrors="$mkerrors"
- mksyscall="./mksyscall.pl -l32 -netbsd -arm"
- mksysnum="curl -s 'http://cvsweb.netbsd.org/bsdweb.cgi/~checkout~/src/sys/kern/syscalls.master' | ./mksysnum_netbsd.pl"
+ mksyscall="go run mksyscall.go -l32 -netbsd -arm"
+ mksysnum="go run mksysnum.go 'http://cvsweb.netbsd.org/bsdweb.cgi/~checkout~/src/sys/kern/syscalls.master'"
# Let the type of C char be signed for making the bare syscall
# API consistent across platforms.
mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
;;
+netbsd_arm64)
+ mkerrors="$mkerrors -m64"
+ mksyscall="go run mksyscall.go -netbsd"
+ mksysnum="go run mksysnum.go 'http://cvsweb.netbsd.org/bsdweb.cgi/~checkout~/src/sys/kern/syscalls.master'"
+ mktypes="GOARCH=$GOARCH go tool cgo -godefs"
+ ;;
openbsd_386)
mkerrors="$mkerrors -m32"
- mksyscall="./mksyscall.pl -l32 -openbsd"
- mksysctl="./mksysctl_openbsd.pl"
- mksysnum="curl -s 'http://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/kern/syscalls.master' | ./mksysnum_openbsd.pl"
+ mksyscall="go run mksyscall.go -l32 -openbsd"
+ mksysctl="go run mksysctl_openbsd.go"
+ mksysnum="go run mksysnum.go 'https://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/kern/syscalls.master'"
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
;;
openbsd_amd64)
mkerrors="$mkerrors -m64"
- mksyscall="./mksyscall.pl -openbsd"
- mksysctl="./mksysctl_openbsd.pl"
- mksysnum="curl -s 'http://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/kern/syscalls.master' | ./mksysnum_openbsd.pl"
+ mksyscall="go run mksyscall.go -openbsd"
+ mksysctl="go run mksysctl_openbsd.go"
+ mksysnum="go run mksysnum.go 'https://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/kern/syscalls.master'"
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
;;
openbsd_arm)
mkerrors="$mkerrors"
- mksyscall="./mksyscall.pl -l32 -openbsd -arm"
- mksysctl="./mksysctl_openbsd.pl"
- mksysnum="curl -s 'http://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/kern/syscalls.master' | ./mksysnum_openbsd.pl"
+ mksyscall="go run mksyscall.go -l32 -openbsd -arm"
+ mksysctl="go run mksysctl_openbsd.go"
+ mksysnum="go run mksysnum.go 'https://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/kern/syscalls.master'"
+ # Let the type of C char be signed for making the bare syscall
+ # API consistent across platforms.
+ mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
+ ;;
+openbsd_arm64)
+ mkerrors="$mkerrors -m64"
+ mksyscall="go run mksyscall.go -openbsd"
+ mksysctl="go run mksysctl_openbsd.go"
+ mksysnum="go run mksysnum.go 'https://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/kern/syscalls.master'"
# Let the type of C char be signed for making the bare syscall
# API consistent across platforms.
mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
;;
solaris_amd64)
- mksyscall="./mksyscall_solaris.pl"
+ mksyscall="go run mksyscall_solaris.go"
mkerrors="$mkerrors -m64"
mksysnum=
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
@@ -183,12 +206,24 @@ esac
syscall_goos="syscall_bsd.go $syscall_goos"
;;
esac
- if [ -n "$mksyscall" ]; then echo "$mksyscall -tags $GOOS,$GOARCH $syscall_goos $GOOSARCH_in |gofmt >zsyscall_$GOOSARCH.go"; fi
- ;;
+ if [ -n "$mksyscall" ]; then
+ if [ "$GOOSARCH" == "aix_ppc64" ]; then
+ # aix/ppc64 script generates files instead of writing to stdin.
+ echo "$mksyscall -tags $GOOS,$GOARCH $syscall_goos $GOOSARCH_in && gofmt -w zsyscall_$GOOSARCH.go && gofmt -w zsyscall_"$GOOSARCH"_gccgo.go && gofmt -w zsyscall_"$GOOSARCH"_gc.go " ;
+ elif [ "$GOOS" == "darwin" ]; then
+ # pre-1.12, direct syscalls
+ echo "$mksyscall -tags $GOOS,$GOARCH,!go1.12 $syscall_goos syscall_darwin_${GOARCH}.1_11.go $GOOSARCH_in |gofmt >zsyscall_$GOOSARCH.1_11.go";
+ # 1.12 and later, syscalls via libSystem
+ echo "$mksyscall -tags $GOOS,$GOARCH,go1.12 $syscall_goos $GOOSARCH_in |gofmt >zsyscall_$GOOSARCH.go";
+ # 1.13 and later, syscalls via libSystem (including syscallPtr)
+ echo "$mksyscall -tags $GOOS,$GOARCH,go1.13 syscall_darwin.1_13.go |gofmt >zsyscall_$GOOSARCH.1_13.go";
+ else
+ echo "$mksyscall -tags $GOOS,$GOARCH $syscall_goos $GOOSARCH_in |gofmt >zsyscall_$GOOSARCH.go";
+ fi
+ fi
esac
if [ -n "$mksysctl" ]; then echo "$mksysctl |gofmt >$zsysctl"; fi
if [ -n "$mksysnum" ]; then echo "$mksysnum |gofmt >zsysnum_$GOOSARCH.go"; fi
- if [ -n "$mktypes" ]; then
- echo "$mktypes types_$GOOS.go | go run mkpost.go > ztypes_$GOOSARCH.go";
- fi
+ if [ -n "$mktypes" ]; then echo "$mktypes types_$GOOS.go | go run mkpost.go > ztypes_$GOOSARCH.go"; fi
+ if [ -n "$mkasm" ]; then echo "$mkasm $GOARCH"; fi
) | $run
diff --git a/vendor/golang.org/x/sys/unix/mkerrors.sh b/vendor/golang.org/x/sys/unix/mkerrors.sh
old mode 100755
new mode 100644
index f9f5e56..6ffac92
--- a/vendor/golang.org/x/sys/unix/mkerrors.sh
+++ b/vendor/golang.org/x/sys/unix/mkerrors.sh
@@ -17,15 +17,17 @@ if test -z "$GOARCH" -o -z "$GOOS"; then
fi
# Check that we are using the new build system if we should
-if [[ "$GOOS" = "linux" ]] && [[ "$GOARCH" != "sparc64" ]]; then
- if [[ "$GOLANG_SYS_BUILD" != "docker" ]]; then
- echo 1>&2 "In the new build system, mkerrors should not be called directly."
- echo 1>&2 "See README.md"
- exit 1
- fi
+if [[ "$GOOS" = "linux" ]] && [[ "$GOLANG_SYS_BUILD" != "docker" ]]; then
+ echo 1>&2 "In the Docker based build system, mkerrors should not be called directly."
+ echo 1>&2 "See README.md"
+ exit 1
fi
-CC=${CC:-cc}
+if [[ "$GOOS" = "aix" ]]; then
+ CC=${CC:-gcc}
+else
+ CC=${CC:-cc}
+fi
if [[ "$GOOS" = "solaris" ]]; then
# Assumes GNU versions of utilities in PATH.
@@ -34,19 +36,40 @@ fi
uname=$(uname)
+includes_AIX='
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define AF_LOCAL AF_UNIX
+'
+
includes_Darwin='
#define _DARWIN_C_SOURCE
#define KERNEL
#define _DARWIN_USE_64_BIT_INODE
+#include
+#include
#include
#include
#include
+#include
#include
#include
#include
#include
#include
+#include
#include
+#include
#include
#include
#include
@@ -59,10 +82,13 @@ includes_Darwin='
includes_DragonFly='
#include
#include
+#include
#include
#include
+#include
#include
#include
+#include
#include
#include
#include
@@ -76,14 +102,17 @@ includes_DragonFly='
'
includes_FreeBSD='
-#include
+#include
#include
#include
#include
+#include
#include
#include
+#include
#include
#include
+#include
#include
#include
#include
@@ -154,37 +183,71 @@ struct ltchars {
#include
#include
#include
+#include
+#include
#include
+#include
#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
#include
+#include
#include
#include
#include
+#include
#include
#include
-#include
-#include
-#include
-#include
+#include
+#include
#include
+#include
+#include
+#include
+#include
+#include
#include
+#include
+#include
#include
+#include
#include
#include
+#include
#include
-#include
#include
#include
-#include
-#include
-#include
#include
-#include
-#include
+#include
#include
-#include
+#include
+#include
+#include
+#include
+
+#include
#include
+
+#if defined(__sparc__)
+// On sparc{,64}, the kernel defines struct termios2 itself which clashes with the
+// definition in glibc. As only the error constants are needed here, include the
+// generic termibits.h (which is included by termbits.h on sparc).
+#include
+#else
#include
+#endif
#ifndef MSG_FASTOPEN
#define MSG_FASTOPEN 0x20000000
@@ -212,13 +275,21 @@ struct ltchars {
#define FS_KEY_DESC_PREFIX "fscrypt:"
#define FS_KEY_DESC_PREFIX_SIZE 8
#define FS_MAX_KEY_SIZE 64
+
+// The code generator produces -0x1 for (~0), but an unsigned value is necessary
+// for the tipc_subscr timeout __u32 field.
+#undef TIPC_WAIT_FOREVER
+#define TIPC_WAIT_FOREVER 0xffffffff
'
includes_NetBSD='
#include
#include
#include
+#include
#include
+#include
+#include
#include
#include
#include
@@ -244,11 +315,15 @@ includes_OpenBSD='
#include
#include
#include
+#include
+#include
#include
#include
+#include
#include
#include
#include
+#include
#include
#include
#include
@@ -278,8 +353,10 @@ includes_OpenBSD='
includes_SunOS='
#include
#include
+#include
#include
#include
+#include
#include
#include
#include
@@ -342,6 +419,7 @@ ccflags="$@"
$2 ~ /^EXTATTR_NAMESPACE_NAMES/ ||
$2 ~ /^EXTATTR_NAMESPACE_[A-Z]+_STRING/ {next}
+ $2 !~ /^ECCAPBITS/ &&
$2 !~ /^ETH_/ &&
$2 !~ /^EPROC_/ &&
$2 !~ /^EQUIV_/ &&
@@ -358,6 +436,7 @@ ccflags="$@"
$2 ~ /^IGN/ ||
$2 ~ /^IX(ON|ANY|OFF)$/ ||
$2 ~ /^IN(LCR|PCK)$/ ||
+ $2 !~ "X86_CR3_PCID_NOFLUSH" &&
$2 ~ /(^FLU?SH)|(FLU?SH$)/ ||
$2 ~ /^C(LOCAL|READ|MSPAR|RTSCTS)$/ ||
$2 == "BRKINT" ||
@@ -367,6 +446,7 @@ ccflags="$@"
$2 == "XCASE" ||
$2 == "ALTWERASE" ||
$2 == "NOKERNINFO" ||
+ $2 == "NFDBITS" ||
$2 ~ /^PAR/ ||
$2 ~ /^SIG[^_]/ ||
$2 ~ /^O[CNPFPL][A-Z]+[^_][A-Z]+$/ ||
@@ -376,21 +456,30 @@ ccflags="$@"
$2 ~ /^TC[IO](ON|OFF)$/ ||
$2 ~ /^IN_/ ||
$2 ~ /^LOCK_(SH|EX|NB|UN)$/ ||
- $2 ~ /^(AF|SOCK|SO|SOL|IPPROTO|IP|IPV6|ICMP6|TCP|EVFILT|NOTE|EV|SHUT|PROT|MAP|PACKET|MSG|SCM|MCL|DT|MADV|PR)_/ ||
+ $2 ~ /^LO_(KEY|NAME)_SIZE$/ ||
+ $2 ~ /^LOOP_(CLR|CTL|GET|SET)_/ ||
+ $2 ~ /^(AF|SOCK|SO|SOL|IPPROTO|IP|IPV6|ICMP6|TCP|MCAST|EVFILT|NOTE|EV|SHUT|PROT|MAP|MFD|T?PACKET|MSG|SCM|MCL|DT|MADV|PR)_/ ||
+ $2 ~ /^TP_STATUS_/ ||
$2 ~ /^FALLOC_/ ||
$2 == "ICMPV6_FILTER" ||
$2 == "SOMAXCONN" ||
$2 == "NAME_MAX" ||
$2 == "IFNAMSIZ" ||
- $2 ~ /^CTL_(MAXNAME|NET|QUERY)$/ ||
+ $2 ~ /^CTL_(HW|KERN|MAXNAME|NET|QUERY)$/ ||
+ $2 ~ /^KERN_(HOSTNAME|OS(RELEASE|TYPE)|VERSION)$/ ||
+ $2 ~ /^HW_MACHINE$/ ||
$2 ~ /^SYSCTL_VERS/ ||
+ $2 !~ "MNT_BITS" &&
$2 ~ /^(MS|MNT|UMOUNT)_/ ||
+ $2 ~ /^NS_GET_/ ||
$2 ~ /^TUN(SET|GET|ATTACH|DETACH)/ ||
- $2 ~ /^(O|F|E?FD|NAME|S|PTRACE|PT)_/ ||
+ $2 ~ /^(O|F|[ES]?FD|NAME|S|PTRACE|PT)_/ ||
+ $2 ~ /^KEXEC_/ ||
$2 ~ /^LINUX_REBOOT_CMD_/ ||
$2 ~ /^LINUX_REBOOT_MAGIC[12]$/ ||
+ $2 ~ /^MODULE_INIT_/ ||
$2 !~ "NLA_TYPE_MASK" &&
- $2 ~ /^(NETLINK|NLM|NLMSG|NLA|IFA|IFAN|RT|RTCF|RTN|RTPROT|RTNH|ARPHRD|ETH_P)_/ ||
+ $2 ~ /^(NETLINK|NLM|NLMSG|NLA|IFA|IFAN|RT|RTC|RTCF|RTN|RTPROT|RTNH|ARPHRD|ETH_P|NETNSA)_/ ||
$2 ~ /^SIOC/ ||
$2 ~ /^TIOC/ ||
$2 ~ /^TCGET/ ||
@@ -403,25 +492,50 @@ ccflags="$@"
$2 ~ /^RLIMIT_(AS|CORE|CPU|DATA|FSIZE|LOCKS|MEMLOCK|MSGQUEUE|NICE|NOFILE|NPROC|RSS|RTPRIO|RTTIME|SIGPENDING|STACK)|RLIM_INFINITY/ ||
$2 ~ /^PRIO_(PROCESS|PGRP|USER)/ ||
$2 ~ /^CLONE_[A-Z_]+/ ||
- $2 !~ /^(BPF_TIMEVAL)$/ &&
+ $2 !~ /^(BPF_TIMEVAL|BPF_FIB_LOOKUP_[A-Z]+)$/ &&
$2 ~ /^(BPF|DLT)_/ ||
- $2 ~ /^CLOCK_/ ||
+ $2 ~ /^(CLOCK|TIMER)_/ ||
$2 ~ /^CAN_/ ||
$2 ~ /^CAP_/ ||
$2 ~ /^ALG_/ ||
- $2 ~ /^FS_(POLICY_FLAGS|KEY_DESC|ENCRYPTION_MODE|[A-Z0-9_]+_KEY_SIZE|IOC_(GET|SET)_ENCRYPTION)/ ||
+ $2 ~ /^FS_(POLICY_FLAGS|KEY_DESC|ENCRYPTION_MODE|[A-Z0-9_]+_KEY_SIZE)/ ||
+ $2 ~ /^FS_IOC_.*ENCRYPTION/ ||
+ $2 ~ /^FSCRYPT_/ ||
$2 ~ /^GRND_/ ||
+ $2 ~ /^RND/ ||
$2 ~ /^KEY_(SPEC|REQKEY_DEFL)_/ ||
$2 ~ /^KEYCTL_/ ||
$2 ~ /^PERF_EVENT_IOC_/ ||
$2 ~ /^SECCOMP_MODE_/ ||
$2 ~ /^SPLICE_/ ||
+ $2 ~ /^SYNC_FILE_RANGE_/ ||
+ $2 !~ /^AUDIT_RECORD_MAGIC/ &&
+ $2 !~ /IOC_MAGIC/ &&
+ $2 ~ /^[A-Z][A-Z0-9_]+_MAGIC2?$/ ||
$2 ~ /^(VM|VMADDR)_/ ||
+ $2 ~ /^IOCTL_VM_SOCKETS_/ ||
$2 ~ /^(TASKSTATS|TS)_/ ||
+ $2 ~ /^CGROUPSTATS_/ ||
$2 ~ /^GENL_/ ||
- $2 ~ /^XATTR_(CREATE|REPLACE)/ ||
+ $2 ~ /^STATX_/ ||
+ $2 ~ /^RENAME/ ||
+ $2 ~ /^UBI_IOC[A-Z]/ ||
+ $2 ~ /^UTIME_/ ||
+ $2 ~ /^XATTR_(CREATE|REPLACE|NO(DEFAULT|FOLLOW|SECURITY)|SHOWCOMPRESSION)/ ||
+ $2 ~ /^ATTR_(BIT_MAP_COUNT|(CMN|VOL|FILE)_)/ ||
+ $2 ~ /^FSOPT_/ ||
+ $2 ~ /^WDIOC_/ ||
+ $2 ~ /^NFN/ ||
+ $2 ~ /^XDP_/ ||
+ $2 ~ /^RWF_/ ||
+ $2 ~ /^(HDIO|WIN|SMART)_/ ||
+ $2 ~ /^CRYPTO_/ ||
+ $2 ~ /^TIPC_/ ||
+ $2 ~ /^DEVLINK_/ ||
$2 !~ "WMESGLEN" &&
$2 ~ /^W[A-Z0-9]+$/ ||
+ $2 ~/^PPPIOC/ ||
+ $2 ~ /^FAN_|FANOTIFY_/ ||
$2 ~ /^BLK[A-Z]*(GET$|SET$|BUF$|PART$|SIZE)/ {printf("\t%s = C.%s\n", $2, $2)}
$2 ~ /^__WCOREFLAG$/ {next}
$2 ~ /^__W[A-Z0-9]+$/ {printf("\t%s = C.%s\n", substr($2,3), $2)}
@@ -443,7 +557,7 @@ errors=$(
signals=$(
echo '#include ' | $CC -x c - -E -dM $ccflags |
awk '$1=="#define" && $2 ~ /^SIG[A-Z0-9]+$/ { print $2 }' |
- egrep -v '(SIGSTKSIZE|SIGSTKSZ|SIGRT)' |
+ egrep -v '(SIGSTKSIZE|SIGSTKSZ|SIGRT|SIGMAX64)' |
sort
)
@@ -453,7 +567,7 @@ echo '#include ' | $CC -x c - -E -dM $ccflags |
sort >_error.grep
echo '#include ' | $CC -x c - -E -dM $ccflags |
awk '$1=="#define" && $2 ~ /^SIG[A-Z0-9]+$/ { print "^\t" $2 "[ \t]*=" }' |
- egrep -v '(SIGSTKSIZE|SIGSTKSZ|SIGRT)' |
+ egrep -v '(SIGSTKSIZE|SIGSTKSZ|SIGRT|SIGMAX64)' |
sort >_signal.grep
echo '// mkerrors.sh' "$@"
@@ -489,21 +603,26 @@ echo ')'
enum { A = 'A', Z = 'Z', a = 'a', z = 'z' }; // avoid need for single quotes below
-int errors[] = {
+struct tuple {
+ int num;
+ const char *name;
+};
+
+struct tuple errors[] = {
"
for i in $errors
do
- echo -E ' '$i,
+ echo -E ' {'$i', "'$i'" },'
done
echo -E "
};
-int signals[] = {
+struct tuple signals[] = {
"
for i in $signals
do
- echo -E ' '$i,
+ echo -E ' {'$i', "'$i'" },'
done
# Use -E because on some systems bash builtin interprets \n itself.
@@ -511,9 +630,9 @@ int signals[] = {
};
static int
-intcmp(const void *a, const void *b)
+tuplecmp(const void *a, const void *b)
{
- return *(int*)a - *(int*)b;
+ return ((struct tuple *)a)->num - ((struct tuple *)b)->num;
}
int
@@ -523,26 +642,34 @@ main(void)
char buf[1024], *p;
printf("\n\n// Error table\n");
- printf("var errors = [...]string {\n");
- qsort(errors, nelem(errors), sizeof errors[0], intcmp);
+ printf("var errorList = [...]struct {\n");
+ printf("\tnum syscall.Errno\n");
+ printf("\tname string\n");
+ printf("\tdesc string\n");
+ printf("} {\n");
+ qsort(errors, nelem(errors), sizeof errors[0], tuplecmp);
for(i=0; i 0 && errors[i-1] == e)
+ e = errors[i].num;
+ if(i > 0 && errors[i-1].num == e)
continue;
strcpy(buf, strerror(e));
// lowercase first letter: Bad -> bad, but STREAM -> STREAM.
if(A <= buf[0] && buf[0] <= Z && a <= buf[1] && buf[1] <= z)
buf[0] += a - A;
- printf("\t%d: \"%s\",\n", e, buf);
+ printf("\t{ %d, \"%s\", \"%s\" },\n", e, errors[i].name, buf);
}
printf("}\n\n");
printf("\n\n// Signal table\n");
- printf("var signals = [...]string {\n");
- qsort(signals, nelem(signals), sizeof signals[0], intcmp);
+ printf("var signalList = [...]struct {\n");
+ printf("\tnum syscall.Signal\n");
+ printf("\tname string\n");
+ printf("\tdesc string\n");
+ printf("} {\n");
+ qsort(signals, nelem(signals), sizeof signals[0], tuplecmp);
for(i=0; i 0 && signals[i-1] == e)
+ e = signals[i].num;
+ if(i > 0 && signals[i-1].num == e)
continue;
strcpy(buf, strsignal(e));
// lowercase first letter: Bad -> bad, but STREAM -> STREAM.
@@ -552,7 +679,7 @@ main(void)
p = strrchr(buf, ":"[0]);
if(p)
*p = '\0';
- printf("\t%d: \"%s\",\n", e, buf);
+ printf("\t{ %d, \"%s\", \"%s\" },\n", e, signals[i].name, buf);
}
printf("}\n\n");
diff --git a/vendor/golang.org/x/sys/unix/mkpost.go b/vendor/golang.org/x/sys/unix/mkpost.go
deleted file mode 100644
index d3ff659..0000000
--- a/vendor/golang.org/x/sys/unix/mkpost.go
+++ /dev/null
@@ -1,88 +0,0 @@
-// 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 ignore
-
-// mkpost processes the output of cgo -godefs to
-// modify the generated types. It is used to clean up
-// the sys API in an architecture specific manner.
-//
-// mkpost is run after cgo -godefs; see README.md.
-package main
-
-import (
- "bytes"
- "fmt"
- "go/format"
- "io/ioutil"
- "log"
- "os"
- "regexp"
-)
-
-func main() {
- // Get the OS and architecture (using GOARCH_TARGET if it exists)
- goos := os.Getenv("GOOS")
- goarch := os.Getenv("GOARCH_TARGET")
- if goarch == "" {
- goarch = os.Getenv("GOARCH")
- }
- // Check that we are using the new build system if we should be.
- if goos == "linux" && goarch != "sparc64" {
- if os.Getenv("GOLANG_SYS_BUILD") != "docker" {
- os.Stderr.WriteString("In the new build system, mkpost should not be called directly.\n")
- os.Stderr.WriteString("See README.md\n")
- os.Exit(1)
- }
- }
-
- b, err := ioutil.ReadAll(os.Stdin)
- if err != nil {
- log.Fatal(err)
- }
-
- // If we have empty Ptrace structs, we should delete them. Only s390x emits
- // nonempty Ptrace structs.
- ptraceRexexp := regexp.MustCompile(`type Ptrace((Psw|Fpregs|Per) struct {\s*})`)
- b = ptraceRexexp.ReplaceAll(b, nil)
-
- // Replace the control_regs union with a blank identifier for now.
- controlRegsRegex := regexp.MustCompile(`(Control_regs)\s+\[0\]uint64`)
- b = controlRegsRegex.ReplaceAll(b, []byte("_ [0]uint64"))
-
- // Remove fields that are added by glibc
- // Note that this is unstable as the identifers are private.
- removeFieldsRegex := regexp.MustCompile(`X__glibc\S*`)
- b = removeFieldsRegex.ReplaceAll(b, []byte("_"))
-
- // We refuse to export private fields on s390x
- if goarch == "s390x" && goos == "linux" {
- // Remove cgo padding fields
- removeFieldsRegex := regexp.MustCompile(`Pad_cgo_\d+`)
- b = removeFieldsRegex.ReplaceAll(b, []byte("_"))
-
- // Remove padding, hidden, or unused fields
- removeFieldsRegex = regexp.MustCompile(`X_\S+`)
- b = removeFieldsRegex.ReplaceAll(b, []byte("_"))
- }
-
- // Remove the first line of warning from cgo
- b = b[bytes.IndexByte(b, '\n')+1:]
- // Modify the command in the header to include:
- // mkpost, our own warning, and a build tag.
- replacement := fmt.Sprintf(`$1 | go run mkpost.go
-// Code generated by the command above; see README.md. DO NOT EDIT.
-
-// +build %s,%s`, goarch, goos)
- cgoCommandRegex := regexp.MustCompile(`(cgo -godefs .*)`)
- b = cgoCommandRegex.ReplaceAll(b, []byte(replacement))
-
- // gofmt
- b, err = format.Source(b)
- if err != nil {
- log.Fatal(err)
- }
-
- os.Stdout.Write(b)
-}
diff --git a/vendor/golang.org/x/sys/unix/mksyscall.pl b/vendor/golang.org/x/sys/unix/mksyscall.pl
deleted file mode 100755
index fb929b4..0000000
--- a/vendor/golang.org/x/sys/unix/mksyscall.pl
+++ /dev/null
@@ -1,328 +0,0 @@
-#!/usr/bin/env perl
-# 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.
-
-# This program reads a file containing function prototypes
-# (like syscall_darwin.go) and generates system call bodies.
-# The prototypes are marked by lines beginning with "//sys"
-# and read like func declarations if //sys is replaced by func, but:
-# * The parameter lists must give a name for each argument.
-# This includes return parameters.
-# * The parameter lists must give a type for each argument:
-# the (x, y, z int) shorthand is not allowed.
-# * If the return parameter is an error number, it must be named errno.
-
-# A line beginning with //sysnb is like //sys, except that the
-# goroutine will not be suspended during the execution of the system
-# call. This must only be used for system calls which can never
-# block, as otherwise the system call could cause all goroutines to
-# hang.
-
-use strict;
-
-my $cmdline = "mksyscall.pl " . join(' ', @ARGV);
-my $errors = 0;
-my $_32bit = "";
-my $plan9 = 0;
-my $openbsd = 0;
-my $netbsd = 0;
-my $dragonfly = 0;
-my $arm = 0; # 64-bit value should use (even, odd)-pair
-my $tags = ""; # build tags
-
-if($ARGV[0] eq "-b32") {
- $_32bit = "big-endian";
- shift;
-} elsif($ARGV[0] eq "-l32") {
- $_32bit = "little-endian";
- shift;
-}
-if($ARGV[0] eq "-plan9") {
- $plan9 = 1;
- shift;
-}
-if($ARGV[0] eq "-openbsd") {
- $openbsd = 1;
- shift;
-}
-if($ARGV[0] eq "-netbsd") {
- $netbsd = 1;
- shift;
-}
-if($ARGV[0] eq "-dragonfly") {
- $dragonfly = 1;
- shift;
-}
-if($ARGV[0] eq "-arm") {
- $arm = 1;
- shift;
-}
-if($ARGV[0] eq "-tags") {
- shift;
- $tags = $ARGV[0];
- shift;
-}
-
-if($ARGV[0] =~ /^-/) {
- print STDERR "usage: mksyscall.pl [-b32 | -l32] [-tags x,y] [file ...]\n";
- exit 1;
-}
-
-# Check that we are using the new build system if we should
-if($ENV{'GOOS'} eq "linux" && $ENV{'GOARCH'} ne "sparc64") {
- if($ENV{'GOLANG_SYS_BUILD'} ne "docker") {
- print STDERR "In the new build system, mksyscall should not be called directly.\n";
- print STDERR "See README.md\n";
- exit 1;
- }
-}
-
-
-sub parseparamlist($) {
- my ($list) = @_;
- $list =~ s/^\s*//;
- $list =~ s/\s*$//;
- if($list eq "") {
- return ();
- }
- return split(/\s*,\s*/, $list);
-}
-
-sub parseparam($) {
- my ($p) = @_;
- if($p !~ /^(\S*) (\S*)$/) {
- print STDERR "$ARGV:$.: malformed parameter: $p\n";
- $errors = 1;
- return ("xx", "int");
- }
- return ($1, $2);
-}
-
-my $text = "";
-while(<>) {
- chomp;
- s/\s+/ /g;
- s/^\s+//;
- s/\s+$//;
- my $nonblock = /^\/\/sysnb /;
- next if !/^\/\/sys / && !$nonblock;
-
- # Line must be of the form
- # func Open(path string, mode int, perm int) (fd int, errno error)
- # Split into name, in params, out params.
- if(!/^\/\/sys(nb)? (\w+)\(([^()]*)\)\s*(?:\(([^()]+)\))?\s*(?:=\s*((?i)SYS_[A-Z0-9_]+))?$/) {
- print STDERR "$ARGV:$.: malformed //sys declaration\n";
- $errors = 1;
- next;
- }
- my ($func, $in, $out, $sysname) = ($2, $3, $4, $5);
-
- # Split argument lists on comma.
- my @in = parseparamlist($in);
- my @out = parseparamlist($out);
-
- # Try in vain to keep people from editing this file.
- # The theory is that they jump into the middle of the file
- # without reading the header.
- $text .= "// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\n\n";
-
- # Go function header.
- my $out_decl = @out ? sprintf(" (%s)", join(', ', @out)) : "";
- $text .= sprintf "func %s(%s)%s {\n", $func, join(', ', @in), $out_decl;
-
- # Check if err return available
- my $errvar = "";
- foreach my $p (@out) {
- my ($name, $type) = parseparam($p);
- if($type eq "error") {
- $errvar = $name;
- last;
- }
- }
-
- # Prepare arguments to Syscall.
- my @args = ();
- my $n = 0;
- foreach my $p (@in) {
- my ($name, $type) = parseparam($p);
- if($type =~ /^\*/) {
- push @args, "uintptr(unsafe.Pointer($name))";
- } elsif($type eq "string" && $errvar ne "") {
- $text .= "\tvar _p$n *byte\n";
- $text .= "\t_p$n, $errvar = BytePtrFromString($name)\n";
- $text .= "\tif $errvar != nil {\n\t\treturn\n\t}\n";
- push @args, "uintptr(unsafe.Pointer(_p$n))";
- $n++;
- } elsif($type eq "string") {
- print STDERR "$ARGV:$.: $func uses string arguments, but has no error return\n";
- $text .= "\tvar _p$n *byte\n";
- $text .= "\t_p$n, _ = BytePtrFromString($name)\n";
- push @args, "uintptr(unsafe.Pointer(_p$n))";
- $n++;
- } elsif($type =~ /^\[\](.*)/) {
- # Convert slice into pointer, length.
- # Have to be careful not to take address of &a[0] if len == 0:
- # pass dummy pointer in that case.
- # Used to pass nil, but some OSes or simulators reject write(fd, nil, 0).
- $text .= "\tvar _p$n unsafe.Pointer\n";
- $text .= "\tif len($name) > 0 {\n\t\t_p$n = unsafe.Pointer(\&${name}[0])\n\t}";
- $text .= " else {\n\t\t_p$n = unsafe.Pointer(&_zero)\n\t}";
- $text .= "\n";
- push @args, "uintptr(_p$n)", "uintptr(len($name))";
- $n++;
- } elsif($type eq "int64" && ($openbsd || $netbsd)) {
- push @args, "0";
- if($_32bit eq "big-endian") {
- push @args, "uintptr($name>>32)", "uintptr($name)";
- } elsif($_32bit eq "little-endian") {
- push @args, "uintptr($name)", "uintptr($name>>32)";
- } else {
- push @args, "uintptr($name)";
- }
- } elsif($type eq "int64" && $dragonfly) {
- if ($func !~ /^extp(read|write)/i) {
- push @args, "0";
- }
- if($_32bit eq "big-endian") {
- push @args, "uintptr($name>>32)", "uintptr($name)";
- } elsif($_32bit eq "little-endian") {
- push @args, "uintptr($name)", "uintptr($name>>32)";
- } else {
- push @args, "uintptr($name)";
- }
- } elsif($type eq "int64" && $_32bit ne "") {
- if(@args % 2 && $arm) {
- # arm abi specifies 64-bit argument uses
- # (even, odd) pair
- push @args, "0"
- }
- if($_32bit eq "big-endian") {
- push @args, "uintptr($name>>32)", "uintptr($name)";
- } else {
- push @args, "uintptr($name)", "uintptr($name>>32)";
- }
- } else {
- push @args, "uintptr($name)";
- }
- }
-
- # Determine which form to use; pad args with zeros.
- my $asm = "Syscall";
- if ($nonblock) {
- $asm = "RawSyscall";
- }
- if(@args <= 3) {
- while(@args < 3) {
- push @args, "0";
- }
- } elsif(@args <= 6) {
- $asm .= "6";
- while(@args < 6) {
- push @args, "0";
- }
- } elsif(@args <= 9) {
- $asm .= "9";
- while(@args < 9) {
- push @args, "0";
- }
- } else {
- print STDERR "$ARGV:$.: too many arguments to system call\n";
- }
-
- # System call number.
- if($sysname eq "") {
- $sysname = "SYS_$func";
- $sysname =~ s/([a-z])([A-Z])/${1}_$2/g; # turn FooBar into Foo_Bar
- $sysname =~ y/a-z/A-Z/;
- }
-
- # Actual call.
- my $args = join(', ', @args);
- my $call = "$asm($sysname, $args)";
-
- # Assign return values.
- my $body = "";
- my @ret = ("_", "_", "_");
- my $do_errno = 0;
- for(my $i=0; $i<@out; $i++) {
- my $p = $out[$i];
- my ($name, $type) = parseparam($p);
- my $reg = "";
- if($name eq "err" && !$plan9) {
- $reg = "e1";
- $ret[2] = $reg;
- $do_errno = 1;
- } elsif($name eq "err" && $plan9) {
- $ret[0] = "r0";
- $ret[2] = "e1";
- next;
- } else {
- $reg = sprintf("r%d", $i);
- $ret[$i] = $reg;
- }
- if($type eq "bool") {
- $reg = "$reg != 0";
- }
- if($type eq "int64" && $_32bit ne "") {
- # 64-bit number in r1:r0 or r0:r1.
- if($i+2 > @out) {
- print STDERR "$ARGV:$.: not enough registers for int64 return\n";
- }
- if($_32bit eq "big-endian") {
- $reg = sprintf("int64(r%d)<<32 | int64(r%d)", $i, $i+1);
- } else {
- $reg = sprintf("int64(r%d)<<32 | int64(r%d)", $i+1, $i);
- }
- $ret[$i] = sprintf("r%d", $i);
- $ret[$i+1] = sprintf("r%d", $i+1);
- }
- if($reg ne "e1" || $plan9) {
- $body .= "\t$name = $type($reg)\n";
- }
- }
- if ($ret[0] eq "_" && $ret[1] eq "_" && $ret[2] eq "_") {
- $text .= "\t$call\n";
- } else {
- $text .= "\t$ret[0], $ret[1], $ret[2] := $call\n";
- }
- $text .= $body;
-
- if ($plan9 && $ret[2] eq "e1") {
- $text .= "\tif int32(r0) == -1 {\n";
- $text .= "\t\terr = e1\n";
- $text .= "\t}\n";
- } elsif ($do_errno) {
- $text .= "\tif e1 != 0 {\n";
- $text .= "\t\terr = errnoErr(e1)\n";
- $text .= "\t}\n";
- }
- $text .= "\treturn\n";
- $text .= "}\n\n";
-}
-
-chomp $text;
-chomp $text;
-
-if($errors) {
- exit 1;
-}
-
-print <) {
- chomp;
- s/\s+/ /g;
- s/^\s+//;
- s/\s+$//;
- $package = $1 if !$package && /^package (\S+)$/;
- my $nonblock = /^\/\/sysnb /;
- next if !/^\/\/sys / && !$nonblock;
-
- # Line must be of the form
- # func Open(path string, mode int, perm int) (fd int, err error)
- # Split into name, in params, out params.
- if(!/^\/\/sys(nb)? (\w+)\(([^()]*)\)\s*(?:\(([^()]+)\))?\s*(?:=\s*(?:(\w*)\.)?(\w*))?$/) {
- print STDERR "$ARGV:$.: malformed //sys declaration\n";
- $errors = 1;
- next;
- }
- my ($nb, $func, $in, $out, $modname, $sysname) = ($1, $2, $3, $4, $5, $6);
-
- # Split argument lists on comma.
- my @in = parseparamlist($in);
- my @out = parseparamlist($out);
-
- # So file name.
- if($modname eq "") {
- $modname = "libc";
- }
-
- # System call name.
- if($sysname eq "") {
- $sysname = "$func";
- }
-
- # System call pointer variable name.
- my $sysvarname = "proc$sysname";
-
- my $strconvfunc = "BytePtrFromString";
- my $strconvtype = "*byte";
-
- $sysname =~ y/A-Z/a-z/; # All libc functions are lowercase.
-
- # Runtime import of function to allow cross-platform builds.
- $dynimports .= "//go:cgo_import_dynamic libc_${sysname} ${sysname} \"$modname.so\"\n";
- # Link symbol to proc address variable.
- $linknames .= "//go:linkname ${sysvarname} libc_${sysname}\n";
- # Library proc address variable.
- push @vars, $sysvarname;
-
- # Go function header.
- $out = join(', ', @out);
- if($out ne "") {
- $out = " ($out)";
- }
- if($text ne "") {
- $text .= "\n"
- }
- $text .= sprintf "func %s(%s)%s {\n", $func, join(', ', @in), $out;
-
- # Check if err return available
- my $errvar = "";
- foreach my $p (@out) {
- my ($name, $type) = parseparam($p);
- if($type eq "error") {
- $errvar = $name;
- last;
- }
- }
-
- # Prepare arguments to Syscall.
- my @args = ();
- my $n = 0;
- foreach my $p (@in) {
- my ($name, $type) = parseparam($p);
- if($type =~ /^\*/) {
- push @args, "uintptr(unsafe.Pointer($name))";
- } elsif($type eq "string" && $errvar ne "") {
- $text .= "\tvar _p$n $strconvtype\n";
- $text .= "\t_p$n, $errvar = $strconvfunc($name)\n";
- $text .= "\tif $errvar != nil {\n\t\treturn\n\t}\n";
- push @args, "uintptr(unsafe.Pointer(_p$n))";
- $n++;
- } elsif($type eq "string") {
- print STDERR "$ARGV:$.: $func uses string arguments, but has no error return\n";
- $text .= "\tvar _p$n $strconvtype\n";
- $text .= "\t_p$n, _ = $strconvfunc($name)\n";
- push @args, "uintptr(unsafe.Pointer(_p$n))";
- $n++;
- } elsif($type =~ /^\[\](.*)/) {
- # Convert slice into pointer, length.
- # Have to be careful not to take address of &a[0] if len == 0:
- # pass nil in that case.
- $text .= "\tvar _p$n *$1\n";
- $text .= "\tif len($name) > 0 {\n\t\t_p$n = \&$name\[0]\n\t}\n";
- push @args, "uintptr(unsafe.Pointer(_p$n))", "uintptr(len($name))";
- $n++;
- } elsif($type eq "int64" && $_32bit ne "") {
- if($_32bit eq "big-endian") {
- push @args, "uintptr($name >> 32)", "uintptr($name)";
- } else {
- push @args, "uintptr($name)", "uintptr($name >> 32)";
- }
- } elsif($type eq "bool") {
- $text .= "\tvar _p$n uint32\n";
- $text .= "\tif $name {\n\t\t_p$n = 1\n\t} else {\n\t\t_p$n = 0\n\t}\n";
- push @args, "uintptr(_p$n)";
- $n++;
- } else {
- push @args, "uintptr($name)";
- }
- }
- my $nargs = @args;
-
- # Determine which form to use; pad args with zeros.
- my $asm = "sysvicall6";
- if ($nonblock) {
- $asm = "rawSysvicall6";
- }
- if(@args <= 6) {
- while(@args < 6) {
- push @args, "0";
- }
- } else {
- print STDERR "$ARGV:$.: too many arguments to system call\n";
- }
-
- # Actual call.
- my $args = join(', ', @args);
- my $call = "$asm(uintptr(unsafe.Pointer(&$sysvarname)), $nargs, $args)";
-
- # Assign return values.
- my $body = "";
- my $failexpr = "";
- my @ret = ("_", "_", "_");
- my @pout= ();
- my $do_errno = 0;
- for(my $i=0; $i<@out; $i++) {
- my $p = $out[$i];
- my ($name, $type) = parseparam($p);
- my $reg = "";
- if($name eq "err") {
- $reg = "e1";
- $ret[2] = $reg;
- $do_errno = 1;
- } else {
- $reg = sprintf("r%d", $i);
- $ret[$i] = $reg;
- }
- if($type eq "bool") {
- $reg = "$reg != 0";
- }
- if($type eq "int64" && $_32bit ne "") {
- # 64-bit number in r1:r0 or r0:r1.
- if($i+2 > @out) {
- print STDERR "$ARGV:$.: not enough registers for int64 return\n";
- }
- if($_32bit eq "big-endian") {
- $reg = sprintf("int64(r%d)<<32 | int64(r%d)", $i, $i+1);
- } else {
- $reg = sprintf("int64(r%d)<<32 | int64(r%d)", $i+1, $i);
- }
- $ret[$i] = sprintf("r%d", $i);
- $ret[$i+1] = sprintf("r%d", $i+1);
- }
- if($reg ne "e1") {
- $body .= "\t$name = $type($reg)\n";
- }
- }
- if ($ret[0] eq "_" && $ret[1] eq "_" && $ret[2] eq "_") {
- $text .= "\t$call\n";
- } else {
- $text .= "\t$ret[0], $ret[1], $ret[2] := $call\n";
- }
- $text .= $body;
-
- if ($do_errno) {
- $text .= "\tif e1 != 0 {\n";
- $text .= "\t\terr = e1\n";
- $text .= "\t}\n";
- }
- $text .= "\treturn\n";
- $text .= "}\n";
-}
-
-if($errors) {
- exit 1;
-}
-
-print < "net.inet",
- "net.inet.ipproto" => "net.inet",
- "net.inet6.ipv6proto" => "net.inet6",
- "net.inet6.ipv6" => "net.inet6.ip6",
- "net.inet.icmpv6" => "net.inet6.icmp6",
- "net.inet6.divert6" => "net.inet6.divert",
- "net.inet6.tcp6" => "net.inet.tcp",
- "net.inet6.udp6" => "net.inet.udp",
- "mpls" => "net.mpls",
- "swpenc" => "vm.swapencrypt"
-);
-
-# Node mappings
-my %node_map = (
- "net.inet.ip.ifq" => "net.ifq",
- "net.inet.pfsync" => "net.pfsync",
- "net.mpls.ifq" => "net.ifq"
-);
-
-my $ctlname;
-my %mib = ();
-my %sysctl = ();
-my $node;
-
-sub debug() {
- print STDERR "$_[0]\n" if $debug;
-}
-
-# Walk the MIB and build a sysctl name to OID mapping.
-sub build_sysctl() {
- my ($node, $name, $oid) = @_;
- my %node = %{$node};
- my @oid = @{$oid};
-
- foreach my $key (sort keys %node) {
- my @node = @{$node{$key}};
- my $nodename = $name.($name ne '' ? '.' : '').$key;
- my @nodeoid = (@oid, $node[0]);
- if ($node[1] eq 'CTLTYPE_NODE') {
- if (exists $node_map{$nodename}) {
- $node = \%mib;
- $ctlname = $node_map{$nodename};
- foreach my $part (split /\./, $ctlname) {
- $node = \%{@{$$node{$part}}[2]};
- }
- } else {
- $node = $node[2];
- }
- &build_sysctl($node, $nodename, \@nodeoid);
- } elsif ($node[1] ne '') {
- $sysctl{$nodename} = \@nodeoid;
- }
- }
-}
-
-foreach my $ctl (@ctls) {
- $ctls{$ctl} = $ctl;
-}
-
-# Build MIB
-foreach my $header (@headers) {
- &debug("Processing $header...");
- open HEADER, "/usr/include/$header" ||
- print STDERR "Failed to open $header\n";
- while () {
- if ($_ =~ /^#define\s+(CTL_NAMES)\s+{/ ||
- $_ =~ /^#define\s+(CTL_(.*)_NAMES)\s+{/ ||
- $_ =~ /^#define\s+((.*)CTL_NAMES)\s+{/) {
- if ($1 eq 'CTL_NAMES') {
- # Top level.
- $node = \%mib;
- } else {
- # Node.
- my $nodename = lc($2);
- if ($header =~ /^netinet\//) {
- $ctlname = "net.inet.$nodename";
- } elsif ($header =~ /^netinet6\//) {
- $ctlname = "net.inet6.$nodename";
- } elsif ($header =~ /^net\//) {
- $ctlname = "net.$nodename";
- } else {
- $ctlname = "$nodename";
- $ctlname =~ s/^(fs|net|kern)_/$1\./;
- }
- if (exists $ctl_map{$ctlname}) {
- $ctlname = $ctl_map{$ctlname};
- }
- if (not exists $ctls{$ctlname}) {
- &debug("Ignoring $ctlname...");
- next;
- }
-
- # Walk down from the top of the MIB.
- $node = \%mib;
- foreach my $part (split /\./, $ctlname) {
- if (not exists $$node{$part}) {
- &debug("Missing node $part");
- $$node{$part} = [ 0, '', {} ];
- }
- $node = \%{@{$$node{$part}}[2]};
- }
- }
-
- # Populate current node with entries.
- my $i = -1;
- while (defined($_) && $_ !~ /^}/) {
- $_ = ;
- $i++ if $_ =~ /{.*}/;
- next if $_ !~ /{\s+"(\w+)",\s+(CTLTYPE_[A-Z]+)\s+}/;
- $$node{$1} = [ $i, $2, {} ];
- }
- }
- }
- close HEADER;
-}
-
-&build_sysctl(\%mib, "", []);
-
-print <){
- if(/^#define\s+SYS_(\w+)\s+([0-9]+)/){
- my $name = $1;
- my $num = $2;
- $name =~ y/a-z/A-Z/;
- print " SYS_$name = $num;"
- }
-}
-
-print <){
- if(/^([0-9]+)\s+STD\s+({ \S+\s+(\w+).*)$/){
- my $num = $1;
- my $proto = $2;
- my $name = "SYS_$3";
- $name =~ y/a-z/A-Z/;
-
- # There are multiple entries for enosys and nosys, so comment them out.
- if($name =~ /^SYS_E?NOSYS$/){
- $name = "// $name";
- }
- if($name eq 'SYS_SYS_EXIT'){
- $name = 'SYS_EXIT';
- }
-
- print " $name = $num; // $proto\n";
- }
-}
-
-print <){
- if(/^([0-9]+)\s+\S+\s+STD\s+({ \S+\s+(\w+).*)$/){
- my $num = $1;
- my $proto = $2;
- my $name = "SYS_$3";
- $name =~ y/a-z/A-Z/;
-
- # There are multiple entries for enosys and nosys, so comment them out.
- if($name =~ /^SYS_E?NOSYS$/){
- $name = "// $name";
- }
- if($name eq 'SYS_SYS_EXIT'){
- $name = 'SYS_EXIT';
- }
-
- print " $name = $num; // $proto\n";
- }
-}
-
-print <){
- if($line =~ /^(.*)\\$/) {
- # Handle continuation
- $line = $1;
- $_ =~ s/^\s+//;
- $line .= $_;
- } else {
- # New line
- $line = $_;
- }
- next if $line =~ /\\$/;
- if($line =~ /^([0-9]+)\s+((STD)|(NOERR))\s+(RUMP\s+)?({\s+\S+\s*\*?\s*\|(\S+)\|(\S*)\|(\w+).*\s+})(\s+(\S+))?$/) {
- my $num = $1;
- my $proto = $6;
- my $compat = $8;
- my $name = "$7_$9";
-
- $name = "$7_$11" if $11 ne '';
- $name =~ y/a-z/A-Z/;
-
- if($compat eq '' || $compat eq '13' || $compat eq '30' || $compat eq '50') {
- print " $name = $num; // $proto\n";
- }
- }
-}
-
-print <){
- if(/^([0-9]+)\s+STD\s+(NOLOCK\s+)?({ \S+\s+\*?(\w+).*)$/){
- my $num = $1;
- my $proto = $3;
- my $name = $4;
- $name =~ y/a-z/A-Z/;
-
- # There are multiple entries for enosys and nosys, so comment them out.
- if($name =~ /^SYS_E?NOSYS$/){
- $name = "// $name";
- }
- if($name eq 'SYS_SYS_EXIT'){
- $name = 'SYS_EXIT';
- }
-
- print " $name = $num; // $proto\n";
- }
-}
-
-print < 6.2, pass execpromises to the syscall.
+ if maj > 6 || (maj == 6 && min > 2) {
+ exptr, err := syscall.BytePtrFromString(execpromises)
+ if err != nil {
+ return err
+ }
+ expr = unsafe.Pointer(exptr)
+ }
+
+ _, _, e := syscall.Syscall(SYS_PLEDGE, uintptr(unsafe.Pointer(pptr)), uintptr(expr), 0)
+ if e != 0 {
+ return e
+ }
+
+ return nil
+}
+
+// PledgePromises implements the pledge syscall.
+//
+// This changes the promises and leaves the execpromises untouched.
+//
+// For more information see pledge(2).
+func PledgePromises(promises string) error {
+ maj, min, err := majmin()
+ if err != nil {
+ return err
+ }
+
+ err = pledgeAvailable(maj, min, "")
+ if err != nil {
+ return err
+ }
+
+ // This variable holds the execpromises and is always nil.
+ var expr unsafe.Pointer
+
+ pptr, err := syscall.BytePtrFromString(promises)
+ if err != nil {
+ return err
+ }
+
+ _, _, e := syscall.Syscall(SYS_PLEDGE, uintptr(unsafe.Pointer(pptr)), uintptr(expr), 0)
+ if e != 0 {
+ return e
+ }
+
+ return nil
+}
+
+// PledgeExecpromises implements the pledge syscall.
+//
+// This changes the execpromises and leaves the promises untouched.
+//
+// For more information see pledge(2).
+func PledgeExecpromises(execpromises string) error {
+ maj, min, err := majmin()
+ if err != nil {
+ return err
+ }
+
+ err = pledgeAvailable(maj, min, execpromises)
+ if err != nil {
+ return err
+ }
+
+ // This variable holds the promises and is always nil.
+ var pptr unsafe.Pointer
+
+ exptr, err := syscall.BytePtrFromString(execpromises)
+ if err != nil {
+ return err
+ }
+
+ _, _, e := syscall.Syscall(SYS_PLEDGE, uintptr(pptr), uintptr(unsafe.Pointer(exptr)), 0)
+ if e != 0 {
+ return e
+ }
+
+ return nil
+}
+
+// majmin returns major and minor version number for an OpenBSD system.
+func majmin() (major int, minor int, err error) {
+ var v Utsname
+ err = Uname(&v)
+ if err != nil {
+ return
+ }
+
+ major, err = strconv.Atoi(string(v.Release[0]))
+ if err != nil {
+ err = errors.New("cannot parse major version number returned by uname")
+ return
+ }
+
+ minor, err = strconv.Atoi(string(v.Release[2]))
+ if err != nil {
+ err = errors.New("cannot parse minor version number returned by uname")
+ return
+ }
+
+ return
+}
+
+// pledgeAvailable checks for availability of the pledge(2) syscall
+// based on the running OpenBSD version.
+func pledgeAvailable(maj, min int, execpromises string) error {
+ // If OpenBSD <= 5.9, pledge is not available.
+ if (maj == 5 && min != 9) || maj < 5 {
+ return fmt.Errorf("pledge syscall is not available on OpenBSD %d.%d", maj, min)
+ }
+
+ // If OpenBSD <= 6.2 and execpromises is not empty,
+ // return an error - execpromises is not available before 6.3
+ if (maj < 6 || (maj == 6 && min <= 2)) && execpromises != "" {
+ return fmt.Errorf("cannot use execpromises on OpenBSD %d.%d", maj, min)
+ }
+
+ return nil
+}
diff --git a/vendor/golang.org/x/sys/unix/race.go b/vendor/golang.org/x/sys/unix/race.go
index 3c7627e..61712b5 100644
--- a/vendor/golang.org/x/sys/unix/race.go
+++ b/vendor/golang.org/x/sys/unix/race.go
@@ -1,4 +1,4 @@
-// Copyright 2012 The Go Authors. All rights reserved.
+// Copyright 2012 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.
diff --git a/vendor/golang.org/x/sys/unix/race0.go b/vendor/golang.org/x/sys/unix/race0.go
index f8678e0..ad02667 100644
--- a/vendor/golang.org/x/sys/unix/race0.go
+++ b/vendor/golang.org/x/sys/unix/race0.go
@@ -1,8 +1,8 @@
-// Copyright 2012 The Go Authors. All rights reserved.
+// Copyright 2012 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 darwin,!race linux,!race freebsd,!race netbsd openbsd solaris dragonfly
+// +build aix darwin,!race linux,!race freebsd,!race netbsd openbsd solaris dragonfly
package unix
diff --git a/vendor/golang.org/x/sys/unix/readdirent_getdents.go b/vendor/golang.org/x/sys/unix/readdirent_getdents.go
new file mode 100644
index 0000000..3a90aa6
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/readdirent_getdents.go
@@ -0,0 +1,12 @@
+// Copyright 2019 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 aix dragonfly freebsd linux netbsd openbsd
+
+package unix
+
+// ReadDirent reads directory entries from fd and writes them into buf.
+func ReadDirent(fd int, buf []byte) (n int, err error) {
+ return Getdents(fd, buf)
+}
diff --git a/vendor/golang.org/x/sys/unix/readdirent_getdirentries.go b/vendor/golang.org/x/sys/unix/readdirent_getdirentries.go
new file mode 100644
index 0000000..5fdae40
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/readdirent_getdirentries.go
@@ -0,0 +1,19 @@
+// Copyright 2019 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 darwin
+
+package unix
+
+import "unsafe"
+
+// ReadDirent reads directory entries from fd and writes them into buf.
+func ReadDirent(fd int, buf []byte) (n int, err error) {
+ // Final argument is (basep *uintptr) and the syscall doesn't take nil.
+ // 64 bits should be enough. (32 bits isn't even on 386). Since the
+ // actual system call is getdirentries64, 64 is a good guess.
+ // TODO(rsc): Can we use a single global basep for all calls?
+ var base = (*uintptr)(unsafe.Pointer(new(uint64)))
+ return Getdirentries(fd, buf, base)
+}
diff --git a/vendor/golang.org/x/sys/unix/sockcmsg_dragonfly.go b/vendor/golang.org/x/sys/unix/sockcmsg_dragonfly.go
new file mode 100644
index 0000000..5144dee
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/sockcmsg_dragonfly.go
@@ -0,0 +1,16 @@
+// Copyright 2019 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 unix
+
+// Round the length of a raw sockaddr up to align it properly.
+func cmsgAlignOf(salen int) int {
+ salign := SizeofPtr
+ if SizeofPtr == 8 && !supportsABI(_dragonflyABIChangeVersion) {
+ // 64-bit Dragonfly before the September 2019 ABI changes still requires
+ // 32-bit aligned access to network subsystem.
+ salign = 4
+ }
+ return (salen + salign - 1) & ^(salign - 1)
+}
diff --git a/vendor/golang.org/x/sys/unix/sockcmsg_linux.go b/vendor/golang.org/x/sys/unix/sockcmsg_linux.go
index d9ff473..8bf4570 100644
--- a/vendor/golang.org/x/sys/unix/sockcmsg_linux.go
+++ b/vendor/golang.org/x/sys/unix/sockcmsg_linux.go
@@ -1,4 +1,4 @@
-// Copyright 2011 The Go Authors. All rights reserved.
+// Copyright 2011 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.
@@ -17,7 +17,7 @@ func UnixCredentials(ucred *Ucred) []byte {
h.Level = SOL_SOCKET
h.Type = SCM_CREDENTIALS
h.SetLen(CmsgLen(SizeofUcred))
- *((*Ucred)(cmsgData(h))) = *ucred
+ *(*Ucred)(h.data(0)) = *ucred
return b
}
diff --git a/vendor/golang.org/x/sys/unix/sockcmsg_unix.go b/vendor/golang.org/x/sys/unix/sockcmsg_unix.go
index bb756ec..003916e 100644
--- a/vendor/golang.org/x/sys/unix/sockcmsg_unix.go
+++ b/vendor/golang.org/x/sys/unix/sockcmsg_unix.go
@@ -2,25 +2,15 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
// Socket control messages
package unix
-import "unsafe"
-
-// Round the length of a raw sockaddr up to align it properly.
-func cmsgAlignOf(salen int) int {
- salign := sizeofPtr
- // NOTE: It seems like 64-bit Darwin, DragonFly BSD and
- // Solaris kernels still require 32-bit aligned access to
- // network subsystem.
- if darwin64Bit || dragonfly64Bit || solaris64Bit {
- salign = 4
- }
- return (salen + salign - 1) & ^(salign - 1)
-}
+import (
+ "unsafe"
+)
// CmsgLen returns the value to store in the Len field of the Cmsghdr
// structure, taking into account any necessary alignment.
@@ -34,8 +24,8 @@ func CmsgSpace(datalen int) int {
return cmsgAlignOf(SizeofCmsghdr) + cmsgAlignOf(datalen)
}
-func cmsgData(h *Cmsghdr) unsafe.Pointer {
- return unsafe.Pointer(uintptr(unsafe.Pointer(h)) + uintptr(cmsgAlignOf(SizeofCmsghdr)))
+func (h *Cmsghdr) data(offset uintptr) unsafe.Pointer {
+ return unsafe.Pointer(uintptr(unsafe.Pointer(h)) + uintptr(cmsgAlignOf(SizeofCmsghdr)) + offset)
}
// SocketControlMessage represents a socket control message.
@@ -78,10 +68,8 @@ func UnixRights(fds ...int) []byte {
h.Level = SOL_SOCKET
h.Type = SCM_RIGHTS
h.SetLen(CmsgLen(datalen))
- data := cmsgData(h)
- for _, fd := range fds {
- *(*int32)(data) = int32(fd)
- data = unsafe.Pointer(uintptr(data) + 4)
+ for i, fd := range fds {
+ *(*int32)(h.data(4 * uintptr(i))) = int32(fd)
}
return b
}
diff --git a/vendor/golang.org/x/sys/unix/sockcmsg_unix_other.go b/vendor/golang.org/x/sys/unix/sockcmsg_unix_other.go
new file mode 100644
index 0000000..7d08dae
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/sockcmsg_unix_other.go
@@ -0,0 +1,38 @@
+// Copyright 2019 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 aix darwin freebsd linux netbsd openbsd solaris
+
+package unix
+
+import (
+ "runtime"
+)
+
+// Round the length of a raw sockaddr up to align it properly.
+func cmsgAlignOf(salen int) int {
+ salign := SizeofPtr
+
+ // dragonfly needs to check ABI version at runtime, see cmsgAlignOf in
+ // sockcmsg_dragonfly.go
+ switch runtime.GOOS {
+ case "aix":
+ // There is no alignment on AIX.
+ salign = 1
+ case "darwin", "illumos", "solaris":
+ // NOTE: It seems like 64-bit Darwin, Illumos and Solaris
+ // kernels still require 32-bit aligned access to network
+ // subsystem.
+ if SizeofPtr == 8 {
+ salign = 4
+ }
+ case "netbsd", "openbsd":
+ // NetBSD and OpenBSD armv7 require 64-bit alignment.
+ if runtime.GOARCH == "arm" {
+ salign = 8
+ }
+ }
+
+ return (salen + salign - 1) & ^(salign - 1)
+}
diff --git a/vendor/golang.org/x/sys/unix/str.go b/vendor/golang.org/x/sys/unix/str.go
index 35ed664..17fb698 100644
--- a/vendor/golang.org/x/sys/unix/str.go
+++ b/vendor/golang.org/x/sys/unix/str.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
package unix
diff --git a/vendor/golang.org/x/sys/unix/syscall.go b/vendor/golang.org/x/sys/unix/syscall.go
index e2ee364..fd4ee8e 100644
--- a/vendor/golang.org/x/sys/unix/syscall.go
+++ b/vendor/golang.org/x/sys/unix/syscall.go
@@ -2,33 +2,36 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
// Package unix contains an interface to the low-level operating system
-// primitives. OS details vary depending on the underlying system, and
+// primitives. OS details vary depending on the underlying system, and
// by default, godoc will display OS-specific documentation for the current
-// system. If you want godoc to display OS documentation for another
-// system, set $GOOS and $GOARCH to the desired system. For example, if
+// system. If you want godoc to display OS documentation for another
+// system, set $GOOS and $GOARCH to the desired system. For example, if
// you want to view documentation for freebsd/arm on linux/amd64, set $GOOS
// to freebsd and $GOARCH to arm.
+//
// The primary use of this package is inside other packages that provide a more
// portable interface to the system, such as "os", "time" and "net". Use
// those packages rather than this one if you can.
+//
// For details of the functions and data types in this package consult
// the manuals for the appropriate operating system.
+//
// These calls return err == nil to indicate success; otherwise
// err represents an operating system error describing the failure and
// holds a value of type syscall.Errno.
-package unix
+package unix // import "golang.org/x/sys/unix"
+
+import "strings"
// ByteSliceFromString returns a NUL-terminated slice of bytes
// containing the text of s. If s contains a NUL byte at any
// location, it returns (nil, EINVAL).
func ByteSliceFromString(s string) ([]byte, error) {
- for i := 0; i < len(s); i++ {
- if s[i] == 0 {
- return nil, EINVAL
- }
+ if strings.IndexByte(s, 0) != -1 {
+ return nil, EINVAL
}
a := make([]byte, len(s)+1)
copy(a, s)
@@ -47,23 +50,4 @@ func BytePtrFromString(s string) (*byte, error) {
}
// Single-word zero for use when we need a valid pointer to 0 bytes.
-// See mkunix.pl.
var _zero uintptr
-
-func (ts *Timespec) Unix() (sec int64, nsec int64) {
- return int64(ts.Sec), int64(ts.Nsec)
-}
-
-func (tv *Timeval) Unix() (sec int64, nsec int64) {
- return int64(tv.Sec), int64(tv.Usec) * 1000
-}
-
-func (ts *Timespec) Nano() int64 {
- return int64(ts.Sec)*1e9 + int64(ts.Nsec)
-}
-
-func (tv *Timeval) Nano() int64 {
- return int64(tv.Sec)*1e9 + int64(tv.Usec)*1000
-}
-
-func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
diff --git a/vendor/golang.org/x/sys/unix/syscall_aix.go b/vendor/golang.org/x/sys/unix/syscall_aix.go
new file mode 100644
index 0000000..9ad8a0d
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/syscall_aix.go
@@ -0,0 +1,536 @@
+// Copyright 2018 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 aix
+
+// Aix system calls.
+// This file is compiled as ordinary Go code,
+// but it is also input to mksyscall,
+// which parses the //sys lines and generates system call stubs.
+// Note that sometimes we use a lowercase //sys name and
+// wrap it in our own nicer implementation.
+
+package unix
+
+import "unsafe"
+
+/*
+ * Wrapped
+ */
+
+//sys utimes(path string, times *[2]Timeval) (err error)
+func Utimes(path string, tv []Timeval) error {
+ if len(tv) != 2 {
+ return EINVAL
+ }
+ return utimes(path, (*[2]Timeval)(unsafe.Pointer(&tv[0])))
+}
+
+//sys utimensat(dirfd int, path string, times *[2]Timespec, flag int) (err error)
+func UtimesNano(path string, ts []Timespec) error {
+ if len(ts) != 2 {
+ return EINVAL
+ }
+ return utimensat(AT_FDCWD, path, (*[2]Timespec)(unsafe.Pointer(&ts[0])), 0)
+}
+
+func UtimesNanoAt(dirfd int, path string, ts []Timespec, flags int) error {
+ if ts == nil {
+ return utimensat(dirfd, path, nil, flags)
+ }
+ if len(ts) != 2 {
+ return EINVAL
+ }
+ return utimensat(dirfd, path, (*[2]Timespec)(unsafe.Pointer(&ts[0])), flags)
+}
+
+func (sa *SockaddrInet4) sockaddr() (unsafe.Pointer, _Socklen, error) {
+ if sa.Port < 0 || sa.Port > 0xFFFF {
+ return nil, 0, EINVAL
+ }
+ sa.raw.Family = AF_INET
+ p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port))
+ p[0] = byte(sa.Port >> 8)
+ p[1] = byte(sa.Port)
+ for i := 0; i < len(sa.Addr); i++ {
+ sa.raw.Addr[i] = sa.Addr[i]
+ }
+ return unsafe.Pointer(&sa.raw), SizeofSockaddrInet4, nil
+}
+
+func (sa *SockaddrInet6) sockaddr() (unsafe.Pointer, _Socklen, error) {
+ if sa.Port < 0 || sa.Port > 0xFFFF {
+ return nil, 0, EINVAL
+ }
+ sa.raw.Family = AF_INET6
+ p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port))
+ p[0] = byte(sa.Port >> 8)
+ p[1] = byte(sa.Port)
+ sa.raw.Scope_id = sa.ZoneId
+ for i := 0; i < len(sa.Addr); i++ {
+ sa.raw.Addr[i] = sa.Addr[i]
+ }
+ return unsafe.Pointer(&sa.raw), SizeofSockaddrInet6, nil
+}
+
+func (sa *SockaddrUnix) sockaddr() (unsafe.Pointer, _Socklen, error) {
+ name := sa.Name
+ n := len(name)
+ if n > len(sa.raw.Path) {
+ return nil, 0, EINVAL
+ }
+ if n == len(sa.raw.Path) && name[0] != '@' {
+ return nil, 0, EINVAL
+ }
+ sa.raw.Family = AF_UNIX
+ for i := 0; i < n; i++ {
+ sa.raw.Path[i] = uint8(name[i])
+ }
+ // length is family (uint16), name, NUL.
+ sl := _Socklen(2)
+ if n > 0 {
+ sl += _Socklen(n) + 1
+ }
+ if sa.raw.Path[0] == '@' {
+ sa.raw.Path[0] = 0
+ // Don't count trailing NUL for abstract address.
+ sl--
+ }
+
+ return unsafe.Pointer(&sa.raw), sl, nil
+}
+
+func Getsockname(fd int) (sa Sockaddr, err error) {
+ var rsa RawSockaddrAny
+ var len _Socklen = SizeofSockaddrAny
+ if err = getsockname(fd, &rsa, &len); err != nil {
+ return
+ }
+ return anyToSockaddr(fd, &rsa)
+}
+
+//sys getcwd(buf []byte) (err error)
+
+const ImplementsGetwd = true
+
+func Getwd() (ret string, err error) {
+ for len := uint64(4096); ; len *= 2 {
+ b := make([]byte, len)
+ err := getcwd(b)
+ if err == nil {
+ i := 0
+ for b[i] != 0 {
+ i++
+ }
+ return string(b[0:i]), nil
+ }
+ if err != ERANGE {
+ return "", err
+ }
+ }
+}
+
+func Getcwd(buf []byte) (n int, err error) {
+ err = getcwd(buf)
+ if err == nil {
+ i := 0
+ for buf[i] != 0 {
+ i++
+ }
+ n = i + 1
+ }
+ return
+}
+
+func Getgroups() (gids []int, err error) {
+ n, err := getgroups(0, nil)
+ if err != nil {
+ return nil, err
+ }
+ if n == 0 {
+ return nil, nil
+ }
+
+ // Sanity check group count. Max is 16 on BSD.
+ if n < 0 || n > 1000 {
+ return nil, EINVAL
+ }
+
+ a := make([]_Gid_t, n)
+ n, err = getgroups(n, &a[0])
+ if err != nil {
+ return nil, err
+ }
+ gids = make([]int, n)
+ for i, v := range a[0:n] {
+ gids[i] = int(v)
+ }
+ return
+}
+
+func Setgroups(gids []int) (err error) {
+ if len(gids) == 0 {
+ return setgroups(0, nil)
+ }
+
+ a := make([]_Gid_t, len(gids))
+ for i, v := range gids {
+ a[i] = _Gid_t(v)
+ }
+ return setgroups(len(a), &a[0])
+}
+
+/*
+ * Socket
+ */
+
+//sys accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error)
+
+func Accept(fd int) (nfd int, sa Sockaddr, err error) {
+ var rsa RawSockaddrAny
+ var len _Socklen = SizeofSockaddrAny
+ nfd, err = accept(fd, &rsa, &len)
+ if nfd == -1 {
+ return
+ }
+ sa, err = anyToSockaddr(fd, &rsa)
+ if err != nil {
+ Close(nfd)
+ nfd = 0
+ }
+ return
+}
+
+func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from Sockaddr, err error) {
+ // Recvmsg not implemented on AIX
+ sa := new(SockaddrUnix)
+ return -1, -1, -1, sa, ENOSYS
+}
+
+func Sendmsg(fd int, p, oob []byte, to Sockaddr, flags int) (err error) {
+ _, err = SendmsgN(fd, p, oob, to, flags)
+ return
+}
+
+func SendmsgN(fd int, p, oob []byte, to Sockaddr, flags int) (n int, err error) {
+ // SendmsgN not implemented on AIX
+ return -1, ENOSYS
+}
+
+func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) {
+ switch rsa.Addr.Family {
+
+ case AF_UNIX:
+ pp := (*RawSockaddrUnix)(unsafe.Pointer(rsa))
+ sa := new(SockaddrUnix)
+
+ // Some versions of AIX have a bug in getsockname (see IV78655).
+ // We can't rely on sa.Len being set correctly.
+ n := SizeofSockaddrUnix - 3 // subtract leading Family, Len, terminating NUL.
+ for i := 0; i < n; i++ {
+ if pp.Path[i] == 0 {
+ n = i
+ break
+ }
+ }
+
+ bytes := (*[10000]byte)(unsafe.Pointer(&pp.Path[0]))[0:n]
+ sa.Name = string(bytes)
+ return sa, nil
+
+ case AF_INET:
+ pp := (*RawSockaddrInet4)(unsafe.Pointer(rsa))
+ sa := new(SockaddrInet4)
+ p := (*[2]byte)(unsafe.Pointer(&pp.Port))
+ sa.Port = int(p[0])<<8 + int(p[1])
+ for i := 0; i < len(sa.Addr); i++ {
+ sa.Addr[i] = pp.Addr[i]
+ }
+ return sa, nil
+
+ case AF_INET6:
+ pp := (*RawSockaddrInet6)(unsafe.Pointer(rsa))
+ sa := new(SockaddrInet6)
+ p := (*[2]byte)(unsafe.Pointer(&pp.Port))
+ sa.Port = int(p[0])<<8 + int(p[1])
+ sa.ZoneId = pp.Scope_id
+ for i := 0; i < len(sa.Addr); i++ {
+ sa.Addr[i] = pp.Addr[i]
+ }
+ return sa, nil
+ }
+ return nil, EAFNOSUPPORT
+}
+
+func Gettimeofday(tv *Timeval) (err error) {
+ err = gettimeofday(tv, nil)
+ return
+}
+
+func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
+ if raceenabled {
+ raceReleaseMerge(unsafe.Pointer(&ioSync))
+ }
+ return sendfile(outfd, infd, offset, count)
+}
+
+// TODO
+func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
+ return -1, ENOSYS
+}
+
+func direntIno(buf []byte) (uint64, bool) {
+ return readInt(buf, unsafe.Offsetof(Dirent{}.Ino), unsafe.Sizeof(Dirent{}.Ino))
+}
+
+func direntReclen(buf []byte) (uint64, bool) {
+ return readInt(buf, unsafe.Offsetof(Dirent{}.Reclen), unsafe.Sizeof(Dirent{}.Reclen))
+}
+
+func direntNamlen(buf []byte) (uint64, bool) {
+ reclen, ok := direntReclen(buf)
+ if !ok {
+ return 0, false
+ }
+ return reclen - uint64(unsafe.Offsetof(Dirent{}.Name)), true
+}
+
+//sys getdirent(fd int, buf []byte) (n int, err error)
+func Getdents(fd int, buf []byte) (n int, err error) {
+ return getdirent(fd, buf)
+}
+
+//sys wait4(pid Pid_t, status *_C_int, options int, rusage *Rusage) (wpid Pid_t, err error)
+func Wait4(pid int, wstatus *WaitStatus, options int, rusage *Rusage) (wpid int, err error) {
+ var status _C_int
+ var r Pid_t
+ err = ERESTART
+ // AIX wait4 may return with ERESTART errno, while the processus is still
+ // active.
+ for err == ERESTART {
+ r, err = wait4(Pid_t(pid), &status, options, rusage)
+ }
+ wpid = int(r)
+ if wstatus != nil {
+ *wstatus = WaitStatus(status)
+ }
+ return
+}
+
+/*
+ * Wait
+ */
+
+type WaitStatus uint32
+
+func (w WaitStatus) Stopped() bool { return w&0x40 != 0 }
+func (w WaitStatus) StopSignal() Signal {
+ if !w.Stopped() {
+ return -1
+ }
+ return Signal(w>>8) & 0xFF
+}
+
+func (w WaitStatus) Exited() bool { return w&0xFF == 0 }
+func (w WaitStatus) ExitStatus() int {
+ if !w.Exited() {
+ return -1
+ }
+ return int((w >> 8) & 0xFF)
+}
+
+func (w WaitStatus) Signaled() bool { return w&0x40 == 0 && w&0xFF != 0 }
+func (w WaitStatus) Signal() Signal {
+ if !w.Signaled() {
+ return -1
+ }
+ return Signal(w>>16) & 0xFF
+}
+
+func (w WaitStatus) Continued() bool { return w&0x01000000 != 0 }
+
+func (w WaitStatus) CoreDump() bool { return w&0x80 == 0x80 }
+
+func (w WaitStatus) TrapCause() int { return -1 }
+
+//sys ioctl(fd int, req uint, arg uintptr) (err error)
+
+// fcntl must never be called with cmd=F_DUP2FD because it doesn't work on AIX
+// There is no way to create a custom fcntl and to keep //sys fcntl easily,
+// Therefore, the programmer must call dup2 instead of fcntl in this case.
+
+// FcntlInt performs a fcntl syscall on fd with the provided command and argument.
+//sys FcntlInt(fd uintptr, cmd int, arg int) (r int,err error) = fcntl
+
+// FcntlFlock performs a fcntl syscall for the F_GETLK, F_SETLK or F_SETLKW command.
+//sys FcntlFlock(fd uintptr, cmd int, lk *Flock_t) (err error) = fcntl
+
+//sys fcntl(fd int, cmd int, arg int) (val int, err error)
+
+/*
+ * Direct access
+ */
+
+//sys Acct(path string) (err error)
+//sys Chdir(path string) (err error)
+//sys Chroot(path string) (err error)
+//sys Close(fd int) (err error)
+//sys Dup(oldfd int) (fd int, err error)
+//sys Exit(code int)
+//sys Faccessat(dirfd int, path string, mode uint32, flags int) (err error)
+//sys Fchdir(fd int) (err error)
+//sys Fchmod(fd int, mode uint32) (err error)
+//sys Fchmodat(dirfd int, path string, mode uint32, flags int) (err error)
+//sys Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error)
+//sys Fdatasync(fd int) (err error)
+//sys Fsync(fd int) (err error)
+// readdir_r
+//sysnb Getpgid(pid int) (pgid int, err error)
+
+//sys Getpgrp() (pid int)
+
+//sysnb Getpid() (pid int)
+//sysnb Getppid() (ppid int)
+//sys Getpriority(which int, who int) (prio int, err error)
+//sysnb Getrusage(who int, rusage *Rusage) (err error)
+//sysnb Getsid(pid int) (sid int, err error)
+//sysnb Kill(pid int, sig Signal) (err error)
+//sys Klogctl(typ int, buf []byte) (n int, err error) = syslog
+//sys Mkdir(dirfd int, path string, mode uint32) (err error)
+//sys Mkdirat(dirfd int, path string, mode uint32) (err error)
+//sys Mkfifo(path string, mode uint32) (err error)
+//sys Mknod(path string, mode uint32, dev int) (err error)
+//sys Mknodat(dirfd int, path string, mode uint32, dev int) (err error)
+//sys Nanosleep(time *Timespec, leftover *Timespec) (err error)
+//sys Open(path string, mode int, perm uint32) (fd int, err error) = open64
+//sys Openat(dirfd int, path string, flags int, mode uint32) (fd int, err error)
+//sys read(fd int, p []byte) (n int, err error)
+//sys Readlink(path string, buf []byte) (n int, err error)
+//sys Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error)
+//sys Setdomainname(p []byte) (err error)
+//sys Sethostname(p []byte) (err error)
+//sysnb Setpgid(pid int, pgid int) (err error)
+//sysnb Setsid() (pid int, err error)
+//sysnb Settimeofday(tv *Timeval) (err error)
+
+//sys Setuid(uid int) (err error)
+//sys Setgid(uid int) (err error)
+
+//sys Setpriority(which int, who int, prio int) (err error)
+//sys Statx(dirfd int, path string, flags int, mask int, stat *Statx_t) (err error)
+//sys Sync()
+//sysnb Times(tms *Tms) (ticks uintptr, err error)
+//sysnb Umask(mask int) (oldmask int)
+//sysnb Uname(buf *Utsname) (err error)
+//sys Unlink(path string) (err error)
+//sys Unlinkat(dirfd int, path string, flags int) (err error)
+//sys Ustat(dev int, ubuf *Ustat_t) (err error)
+//sys write(fd int, p []byte) (n int, err error)
+//sys readlen(fd int, p *byte, np int) (n int, err error) = read
+//sys writelen(fd int, p *byte, np int) (n int, err error) = write
+
+//sys Dup2(oldfd int, newfd int) (err error)
+//sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = posix_fadvise64
+//sys Fchown(fd int, uid int, gid int) (err error)
+//sys fstat(fd int, stat *Stat_t) (err error)
+//sys fstatat(dirfd int, path string, stat *Stat_t, flags int) (err error) = fstatat
+//sys Fstatfs(fd int, buf *Statfs_t) (err error)
+//sys Ftruncate(fd int, length int64) (err error)
+//sysnb Getegid() (egid int)
+//sysnb Geteuid() (euid int)
+//sysnb Getgid() (gid int)
+//sysnb Getuid() (uid int)
+//sys Lchown(path string, uid int, gid int) (err error)
+//sys Listen(s int, n int) (err error)
+//sys lstat(path string, stat *Stat_t) (err error)
+//sys Pause() (err error)
+//sys Pread(fd int, p []byte, offset int64) (n int, err error) = pread64
+//sys Pwrite(fd int, p []byte, offset int64) (n int, err error) = pwrite64
+//sys Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err error)
+//sys Pselect(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timespec, sigmask *Sigset_t) (n int, err error)
+//sysnb Setregid(rgid int, egid int) (err error)
+//sysnb Setreuid(ruid int, euid int) (err error)
+//sys Shutdown(fd int, how int) (err error)
+//sys Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, err error)
+//sys stat(path string, statptr *Stat_t) (err error)
+//sys Statfs(path string, buf *Statfs_t) (err error)
+//sys Truncate(path string, length int64) (err error)
+
+//sys bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error)
+//sys connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error)
+//sysnb getgroups(n int, list *_Gid_t) (nn int, err error)
+//sysnb setgroups(n int, list *_Gid_t) (err error)
+//sys getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error)
+//sys setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error)
+//sysnb socket(domain int, typ int, proto int) (fd int, err error)
+//sysnb socketpair(domain int, typ int, proto int, fd *[2]int32) (err error)
+//sysnb getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error)
+//sysnb getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error)
+//sys recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error)
+//sys sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error)
+
+// In order to use msghdr structure with Control, Controllen, nrecvmsg and nsendmsg must be used.
+//sys recvmsg(s int, msg *Msghdr, flags int) (n int, err error) = nrecvmsg
+//sys sendmsg(s int, msg *Msghdr, flags int) (n int, err error) = nsendmsg
+
+//sys munmap(addr uintptr, length uintptr) (err error)
+
+var mapper = &mmapper{
+ active: make(map[*byte][]byte),
+ mmap: mmap,
+ munmap: munmap,
+}
+
+func Mmap(fd int, offset int64, length int, prot int, flags int) (data []byte, err error) {
+ return mapper.Mmap(fd, offset, length, prot, flags)
+}
+
+func Munmap(b []byte) (err error) {
+ return mapper.Munmap(b)
+}
+
+//sys Madvise(b []byte, advice int) (err error)
+//sys Mprotect(b []byte, prot int) (err error)
+//sys Mlock(b []byte) (err error)
+//sys Mlockall(flags int) (err error)
+//sys Msync(b []byte, flags int) (err error)
+//sys Munlock(b []byte) (err error)
+//sys Munlockall() (err error)
+
+//sysnb pipe(p *[2]_C_int) (err error)
+
+func Pipe(p []int) (err error) {
+ if len(p) != 2 {
+ return EINVAL
+ }
+ var pp [2]_C_int
+ err = pipe(&pp)
+ p[0] = int(pp[0])
+ p[1] = int(pp[1])
+ return
+}
+
+//sys poll(fds *PollFd, nfds int, timeout int) (n int, err error)
+
+func Poll(fds []PollFd, timeout int) (n int, err error) {
+ if len(fds) == 0 {
+ return poll(nil, 0, timeout)
+ }
+ return poll(&fds[0], len(fds), timeout)
+}
+
+//sys gettimeofday(tv *Timeval, tzp *Timezone) (err error)
+//sysnb Time(t *Time_t) (tt Time_t, err error)
+//sys Utime(path string, buf *Utimbuf) (err error)
+
+//sys Getsystemcfg(label int) (n uint64)
+
+//sys umount(target string) (err error)
+func Unmount(target string, flags int) (err error) {
+ if flags != 0 {
+ // AIX doesn't have any flags for umount.
+ return ENOSYS
+ }
+ return umount(target)
+}
diff --git a/vendor/golang.org/x/sys/unix/syscall_aix_ppc.go b/vendor/golang.org/x/sys/unix/syscall_aix_ppc.go
new file mode 100644
index 0000000..b3c8e33
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/syscall_aix_ppc.go
@@ -0,0 +1,54 @@
+// Copyright 2018 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 aix
+// +build ppc
+
+package unix
+
+//sysnb Getrlimit(resource int, rlim *Rlimit) (err error) = getrlimit64
+//sysnb Setrlimit(resource int, rlim *Rlimit) (err error) = setrlimit64
+//sys Seek(fd int, offset int64, whence int) (off int64, err error) = lseek64
+
+//sys mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, err error)
+
+func setTimespec(sec, nsec int64) Timespec {
+ return Timespec{Sec: int32(sec), Nsec: int32(nsec)}
+}
+
+func setTimeval(sec, usec int64) Timeval {
+ return Timeval{Sec: int32(sec), Usec: int32(usec)}
+}
+
+func (iov *Iovec) SetLen(length int) {
+ iov.Len = uint32(length)
+}
+
+func (msghdr *Msghdr) SetControllen(length int) {
+ msghdr.Controllen = uint32(length)
+}
+
+func (msghdr *Msghdr) SetIovlen(length int) {
+ msghdr.Iovlen = int32(length)
+}
+
+func (cmsg *Cmsghdr) SetLen(length int) {
+ cmsg.Len = uint32(length)
+}
+
+func Fstat(fd int, stat *Stat_t) error {
+ return fstat(fd, stat)
+}
+
+func Fstatat(dirfd int, path string, stat *Stat_t, flags int) error {
+ return fstatat(dirfd, path, stat, flags)
+}
+
+func Lstat(path string, stat *Stat_t) error {
+ return lstat(path, stat)
+}
+
+func Stat(path string, statptr *Stat_t) error {
+ return stat(path, statptr)
+}
diff --git a/vendor/golang.org/x/sys/unix/syscall_aix_ppc64.go b/vendor/golang.org/x/sys/unix/syscall_aix_ppc64.go
new file mode 100644
index 0000000..9a6e024
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/syscall_aix_ppc64.go
@@ -0,0 +1,85 @@
+// Copyright 2018 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 aix
+// +build ppc64
+
+package unix
+
+//sysnb Getrlimit(resource int, rlim *Rlimit) (err error)
+//sysnb Setrlimit(resource int, rlim *Rlimit) (err error)
+//sys Seek(fd int, offset int64, whence int) (off int64, err error) = lseek
+
+//sys mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, err error) = mmap64
+
+func setTimespec(sec, nsec int64) Timespec {
+ return Timespec{Sec: sec, Nsec: nsec}
+}
+
+func setTimeval(sec, usec int64) Timeval {
+ return Timeval{Sec: int64(sec), Usec: int32(usec)}
+}
+
+func (iov *Iovec) SetLen(length int) {
+ iov.Len = uint64(length)
+}
+
+func (msghdr *Msghdr) SetControllen(length int) {
+ msghdr.Controllen = uint32(length)
+}
+
+func (msghdr *Msghdr) SetIovlen(length int) {
+ msghdr.Iovlen = int32(length)
+}
+
+func (cmsg *Cmsghdr) SetLen(length int) {
+ cmsg.Len = uint32(length)
+}
+
+// In order to only have Timespec structure, type of Stat_t's fields
+// Atim, Mtim and Ctim is changed from StTimespec to Timespec during
+// ztypes generation.
+// On ppc64, Timespec.Nsec is an int64 while StTimespec.Nsec is an
+// int32, so the fields' value must be modified.
+func fixStatTimFields(stat *Stat_t) {
+ stat.Atim.Nsec >>= 32
+ stat.Mtim.Nsec >>= 32
+ stat.Ctim.Nsec >>= 32
+}
+
+func Fstat(fd int, stat *Stat_t) error {
+ err := fstat(fd, stat)
+ if err != nil {
+ return err
+ }
+ fixStatTimFields(stat)
+ return nil
+}
+
+func Fstatat(dirfd int, path string, stat *Stat_t, flags int) error {
+ err := fstatat(dirfd, path, stat, flags)
+ if err != nil {
+ return err
+ }
+ fixStatTimFields(stat)
+ return nil
+}
+
+func Lstat(path string, stat *Stat_t) error {
+ err := lstat(path, stat)
+ if err != nil {
+ return err
+ }
+ fixStatTimFields(stat)
+ return nil
+}
+
+func Stat(path string, statptr *Stat_t) error {
+ err := stat(path, statptr)
+ if err != nil {
+ return err
+ }
+ fixStatTimFields(statptr)
+ return nil
+}
diff --git a/vendor/golang.org/x/sys/unix/syscall_bsd.go b/vendor/golang.org/x/sys/unix/syscall_bsd.go
index c2846b3..c704054 100644
--- a/vendor/golang.org/x/sys/unix/syscall_bsd.go
+++ b/vendor/golang.org/x/sys/unix/syscall_bsd.go
@@ -34,7 +34,7 @@ func Getgroups() (gids []int, err error) {
return nil, nil
}
- // Sanity check group count. Max is 16 on BSD.
+ // Sanity check group count. Max is 16 on BSD.
if n < 0 || n > 1000 {
return nil, EINVAL
}
@@ -63,15 +63,6 @@ func Setgroups(gids []int) (err error) {
return setgroups(len(a), &a[0])
}
-func ReadDirent(fd int, buf []byte) (n int, err error) {
- // Final argument is (basep *uintptr) and the syscall doesn't take nil.
- // 64 bits should be enough. (32 bits isn't even on 386). Since the
- // actual system call is getdirentries64, 64 is a good guess.
- // TODO(rsc): Can we use a single global basep for all calls?
- var base = (*uintptr)(unsafe.Pointer(new(uint64)))
- return Getdirentries(fd, buf, base)
-}
-
// Wait status is 7 bits at bottom, either 0 (exited),
// 0x7F (stopped), or a signal number that caused an exit.
// The 0x80 bit is whether there was a core dump.
@@ -86,6 +77,7 @@ const (
shift = 8
exited = 0
+ killed = 9
stopped = 0x7F
)
@@ -112,6 +104,8 @@ func (w WaitStatus) CoreDump() bool { return w.Signaled() && w&core != 0 }
func (w WaitStatus) Stopped() bool { return w&mask == stopped && syscall.Signal(w>>shift) != SIGSTOP }
+func (w WaitStatus) Killed() bool { return w&mask == killed && syscall.Signal(w>>shift) != SIGKILL }
+
func (w WaitStatus) Continued() bool { return w&mask == stopped && syscall.Signal(w>>shift) == SIGSTOP }
func (w WaitStatus) StopSignal() syscall.Signal {
@@ -206,7 +200,7 @@ func (sa *SockaddrDatalink) sockaddr() (unsafe.Pointer, _Socklen, error) {
return unsafe.Pointer(&sa.raw), SizeofSockaddrDatalink, nil
}
-func anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, error) {
+func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) {
switch rsa.Addr.Family {
case AF_LINK:
pp := (*RawSockaddrDatalink)(unsafe.Pointer(rsa))
@@ -243,7 +237,7 @@ func anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, error) {
break
}
}
- bytes := (*[10000]byte)(unsafe.Pointer(&pp.Path[0]))[0:n]
+ bytes := (*[len(pp.Path)]byte)(unsafe.Pointer(&pp.Path[0]))[0:n]
sa.Name = string(bytes)
return sa, nil
@@ -286,7 +280,7 @@ func Accept(fd int) (nfd int, sa Sockaddr, err error) {
Close(nfd)
return 0, nil, ECONNABORTED
}
- sa, err = anyToSockaddr(&rsa)
+ sa, err = anyToSockaddr(fd, &rsa)
if err != nil {
Close(nfd)
nfd = 0
@@ -306,50 +300,21 @@ func Getsockname(fd int) (sa Sockaddr, err error) {
rsa.Addr.Family = AF_UNIX
rsa.Addr.Len = SizeofSockaddrUnix
}
- return anyToSockaddr(&rsa)
+ return anyToSockaddr(fd, &rsa)
}
//sysnb socketpair(domain int, typ int, proto int, fd *[2]int32) (err error)
-func GetsockoptByte(fd, level, opt int) (value byte, err error) {
- var n byte
- vallen := _Socklen(1)
- err = getsockopt(fd, level, opt, unsafe.Pointer(&n), &vallen)
- return n, err
-}
-
-func GetsockoptInet4Addr(fd, level, opt int) (value [4]byte, err error) {
- vallen := _Socklen(4)
- err = getsockopt(fd, level, opt, unsafe.Pointer(&value[0]), &vallen)
- return value, err
-}
-
-func GetsockoptIPMreq(fd, level, opt int) (*IPMreq, error) {
- var value IPMreq
- vallen := _Socklen(SizeofIPMreq)
- err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen)
- return &value, err
-}
-
-func GetsockoptIPv6Mreq(fd, level, opt int) (*IPv6Mreq, error) {
- var value IPv6Mreq
- vallen := _Socklen(SizeofIPv6Mreq)
- err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen)
- return &value, err
-}
-
-func GetsockoptIPv6MTUInfo(fd, level, opt int) (*IPv6MTUInfo, error) {
- var value IPv6MTUInfo
- vallen := _Socklen(SizeofIPv6MTUInfo)
- err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen)
- return &value, err
-}
-
-func GetsockoptICMPv6Filter(fd, level, opt int) (*ICMPv6Filter, error) {
- var value ICMPv6Filter
- vallen := _Socklen(SizeofICMPv6Filter)
- err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen)
- return &value, err
+// GetsockoptString returns the string value of the socket option opt for the
+// socket associated with fd at the given socket level.
+func GetsockoptString(fd, level, opt int) (string, error) {
+ buf := make([]byte, 256)
+ vallen := _Socklen(len(buf))
+ err := getsockopt(fd, level, opt, unsafe.Pointer(&buf[0]), &vallen)
+ if err != nil {
+ return "", err
+ }
+ return string(buf[:vallen-1]), nil
}
//sys recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error)
@@ -385,7 +350,7 @@ func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from
recvflags = int(msg.Flags)
// source address is only specified if the socket is unconnected
if rsa.Addr.Family != AF_UNSPEC {
- from, err = anyToSockaddr(&rsa)
+ from, err = anyToSockaddr(fd, &rsa)
}
return
}
@@ -448,8 +413,6 @@ func Kevent(kq int, changes, events []Kevent_t, timeout *Timespec) (n int, err e
return kevent(kq, change, len(changes), event, len(events), timeout)
}
-//sys sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) = SYS___SYSCTL
-
// sysctlmib translates name to mib number and appends any additional args.
func sysctlmib(name string, args ...int) ([]_C_int, error) {
// Translate name to mib number.
@@ -570,7 +533,12 @@ func UtimesNano(path string, ts []Timespec) error {
if len(ts) != 2 {
return EINVAL
}
- err := utimensat(AT_FDCWD, path, (*[2]Timespec)(unsafe.Pointer(&ts[0])), 0)
+ // Darwin setattrlist can set nanosecond timestamps
+ err := setattrlistTimes(path, ts, 0)
+ if err != ENOSYS {
+ return err
+ }
+ err = utimensat(AT_FDCWD, path, (*[2]Timespec)(unsafe.Pointer(&ts[0])), 0)
if err != ENOSYS {
return err
}
@@ -590,6 +558,10 @@ func UtimesNanoAt(dirfd int, path string, ts []Timespec, flags int) error {
if len(ts) != 2 {
return EINVAL
}
+ err := setattrlistTimes(path, ts, flags)
+ if err != ENOSYS {
+ return err
+ }
return utimensat(dirfd, path, (*[2]Timespec)(unsafe.Pointer(&ts[0])), flags)
}
@@ -605,7 +577,14 @@ func Futimes(fd int, tv []Timeval) error {
return futimes(fd, (*[2]Timeval)(unsafe.Pointer(&tv[0])))
}
-//sys fcntl(fd int, cmd int, arg int) (val int, err error)
+//sys poll(fds *PollFd, nfds int, timeout int) (n int, err error)
+
+func Poll(fds []PollFd, timeout int) (n int, err error) {
+ if len(fds) == 0 {
+ return poll(nil, 0, timeout)
+ }
+ return poll(&fds[0], len(fds), timeout)
+}
// TODO: wrap
// Acct(name nil-string) (err error)
diff --git a/vendor/golang.org/x/sys/unix/syscall_darwin.1_12.go b/vendor/golang.org/x/sys/unix/syscall_darwin.1_12.go
new file mode 100644
index 0000000..6a15cba
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/syscall_darwin.1_12.go
@@ -0,0 +1,29 @@
+// Copyright 2019 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 darwin,go1.12,!go1.13
+
+package unix
+
+import (
+ "unsafe"
+)
+
+func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
+ // To implement this using libSystem we'd need syscall_syscallPtr for
+ // fdopendir. However, syscallPtr was only added in Go 1.13, so we fall
+ // back to raw syscalls for this func on Go 1.12.
+ var p unsafe.Pointer
+ if len(buf) > 0 {
+ p = unsafe.Pointer(&buf[0])
+ } else {
+ p = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := Syscall6(SYS_GETDIRENTRIES64, uintptr(fd), uintptr(p), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0)
+ n = int(r0)
+ if e1 != 0 {
+ return n, errnoErr(e1)
+ }
+ return n, nil
+}
diff --git a/vendor/golang.org/x/sys/unix/syscall_darwin.1_13.go b/vendor/golang.org/x/sys/unix/syscall_darwin.1_13.go
new file mode 100644
index 0000000..f911617
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/syscall_darwin.1_13.go
@@ -0,0 +1,101 @@
+// Copyright 2019 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 darwin,go1.13
+
+package unix
+
+import "unsafe"
+
+//sys closedir(dir uintptr) (err error)
+//sys readdir_r(dir uintptr, entry *Dirent, result **Dirent) (res Errno)
+
+func fdopendir(fd int) (dir uintptr, err error) {
+ r0, _, e1 := syscall_syscallPtr(funcPC(libc_fdopendir_trampoline), uintptr(fd), 0, 0)
+ dir = uintptr(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+func libc_fdopendir_trampoline()
+
+//go:linkname libc_fdopendir libc_fdopendir
+//go:cgo_import_dynamic libc_fdopendir fdopendir "/usr/lib/libSystem.B.dylib"
+
+func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
+ // Simulate Getdirentries using fdopendir/readdir_r/closedir.
+ // We store the number of entries to skip in the seek
+ // offset of fd. See issue #31368.
+ // It's not the full required semantics, but should handle the case
+ // of calling Getdirentries or ReadDirent repeatedly.
+ // It won't handle assigning the results of lseek to *basep, or handle
+ // the directory being edited underfoot.
+ skip, err := Seek(fd, 0, 1 /* SEEK_CUR */)
+ if err != nil {
+ return 0, err
+ }
+
+ // We need to duplicate the incoming file descriptor
+ // because the caller expects to retain control of it, but
+ // fdopendir expects to take control of its argument.
+ // Just Dup'ing the file descriptor is not enough, as the
+ // result shares underlying state. Use Openat to make a really
+ // new file descriptor referring to the same directory.
+ fd2, err := Openat(fd, ".", O_RDONLY, 0)
+ if err != nil {
+ return 0, err
+ }
+ d, err := fdopendir(fd2)
+ if err != nil {
+ Close(fd2)
+ return 0, err
+ }
+ defer closedir(d)
+
+ var cnt int64
+ for {
+ var entry Dirent
+ var entryp *Dirent
+ e := readdir_r(d, &entry, &entryp)
+ if e != 0 {
+ return n, errnoErr(e)
+ }
+ if entryp == nil {
+ break
+ }
+ if skip > 0 {
+ skip--
+ cnt++
+ continue
+ }
+ reclen := int(entry.Reclen)
+ if reclen > len(buf) {
+ // Not enough room. Return for now.
+ // The counter will let us know where we should start up again.
+ // Note: this strategy for suspending in the middle and
+ // restarting is O(n^2) in the length of the directory. Oh well.
+ break
+ }
+ // Copy entry into return buffer.
+ s := struct {
+ ptr unsafe.Pointer
+ siz int
+ cap int
+ }{ptr: unsafe.Pointer(&entry), siz: reclen, cap: reclen}
+ copy(buf, *(*[]byte)(unsafe.Pointer(&s)))
+ buf = buf[reclen:]
+ n += reclen
+ cnt++
+ }
+ // Set the seek offset of the input fd to record
+ // how many files we've already returned.
+ _, err = Seek(fd, cnt, 0 /* SEEK_SET */)
+ if err != nil {
+ return n, err
+ }
+
+ return n, nil
+}
diff --git a/vendor/golang.org/x/sys/unix/syscall_darwin.go b/vendor/golang.org/x/sys/unix/syscall_darwin.go
index ad74a11..3440c52 100644
--- a/vendor/golang.org/x/sys/unix/syscall_darwin.go
+++ b/vendor/golang.org/x/sys/unix/syscall_darwin.go
@@ -13,7 +13,7 @@
package unix
import (
- errorspkg "errors"
+ "errors"
"syscall"
"unsafe"
)
@@ -36,6 +36,7 @@ func Getwd() (string, error) {
return "", ENOTSUP
}
+// SockaddrDatalink implements the Sockaddr interface for AF_LINK type sockets.
type SockaddrDatalink struct {
Len uint8
Family uint8
@@ -54,7 +55,7 @@ func nametomib(name string) (mib []_C_int, err error) {
// NOTE(rsc): It seems strange to set the buffer to have
// size CTL_MAXNAME+2 but use only CTL_MAXNAME
- // as the size. I don't know why the +2 is here, but the
+ // as the size. I don't know why the +2 is here, but the
// kernel uses +2 for its own implementation of this function.
// I am scared that if we don't include the +2 here, the kernel
// will silently write 2 words farther than we specify
@@ -88,7 +89,6 @@ func direntNamlen(buf []byte) (uint64, bool) {
return readInt(buf, unsafe.Offsetof(Dirent{}.Namlen), unsafe.Sizeof(Dirent{}.Namlen))
}
-//sys ptrace(request int, pid int, addr uintptr, data uintptr) (err error)
func PtraceAttach(pid int) (err error) { return ptrace(PT_ATTACH, pid, 0, 0) }
func PtraceDetach(pid int) (err error) { return ptrace(PT_DETACH, pid, 0, 0) }
@@ -109,7 +109,7 @@ type attrList struct {
func getAttrList(path string, attrList attrList, attrBuf []byte, options uint) (attrs [][]byte, err error) {
if len(attrBuf) < 4 {
- return nil, errorspkg.New("attrBuf too small")
+ return nil, errors.New("attrBuf too small")
}
attrList.bitmapCount = attrBitMapCount
@@ -119,17 +119,8 @@ func getAttrList(path string, attrList attrList, attrBuf []byte, options uint) (
return nil, err
}
- _, _, e1 := Syscall6(
- SYS_GETATTRLIST,
- uintptr(unsafe.Pointer(_p0)),
- uintptr(unsafe.Pointer(&attrList)),
- uintptr(unsafe.Pointer(&attrBuf[0])),
- uintptr(len(attrBuf)),
- uintptr(options),
- 0,
- )
- if e1 != 0 {
- return nil, e1
+ if err := getattrlist(_p0, unsafe.Pointer(&attrList), unsafe.Pointer(&attrBuf[0]), uintptr(len(attrBuf)), int(options)); err != nil {
+ return nil, err
}
size := *(*uint32)(unsafe.Pointer(&attrBuf[0]))
@@ -145,12 +136,12 @@ func getAttrList(path string, attrList attrList, attrBuf []byte, options uint) (
for i := uint32(0); int(i) < len(dat); {
header := dat[i:]
if len(header) < 8 {
- return attrs, errorspkg.New("truncated attribute header")
+ return attrs, errors.New("truncated attribute header")
}
datOff := *(*int32)(unsafe.Pointer(&header[0]))
attrLen := *(*uint32)(unsafe.Pointer(&header[4]))
if datOff < 0 || uint32(datOff)+attrLen > uint32(len(dat)) {
- return attrs, errorspkg.New("truncated results; attrBuf too small")
+ return attrs, errors.New("truncated results; attrBuf too small")
}
end := uint32(datOff) + attrLen
attrs = append(attrs, dat[datOff:end])
@@ -162,6 +153,25 @@ func getAttrList(path string, attrList attrList, attrBuf []byte, options uint) (
return
}
+//sys getattrlist(path *byte, list unsafe.Pointer, buf unsafe.Pointer, size uintptr, options int) (err error)
+
+func SysctlClockinfo(name string) (*Clockinfo, error) {
+ mib, err := sysctlmib(name)
+ if err != nil {
+ return nil, err
+ }
+
+ n := uintptr(SizeofClockinfo)
+ var ci Clockinfo
+ if err := sysctl(mib, (*byte)(unsafe.Pointer(&ci)), &n, nil, 0); err != nil {
+ return nil, err
+ }
+ if n != SizeofClockinfo {
+ return nil, EIO
+ }
+ return &ci, nil
+}
+
//sysnb pipe() (r int, w int, err error)
func Pipe(p []int) (err error) {
@@ -179,14 +189,141 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
_p0 = unsafe.Pointer(&buf[0])
bufsize = unsafe.Sizeof(Statfs_t{}) * uintptr(len(buf))
}
- r0, _, e1 := Syscall(SYS_GETFSSTAT64, uintptr(_p0), bufsize, uintptr(flags))
- n = int(r0)
- if e1 != 0 {
- err = e1
- }
- return
+ return getfsstat(_p0, bufsize, flags)
}
+func xattrPointer(dest []byte) *byte {
+ // It's only when dest is set to NULL that the OS X implementations of
+ // getxattr() and listxattr() return the current sizes of the named attributes.
+ // An empty byte array is not sufficient. To maintain the same behaviour as the
+ // linux implementation, we wrap around the system calls and pass in NULL when
+ // dest is empty.
+ var destp *byte
+ if len(dest) > 0 {
+ destp = &dest[0]
+ }
+ return destp
+}
+
+//sys getxattr(path string, attr string, dest *byte, size int, position uint32, options int) (sz int, err error)
+
+func Getxattr(path string, attr string, dest []byte) (sz int, err error) {
+ return getxattr(path, attr, xattrPointer(dest), len(dest), 0, 0)
+}
+
+func Lgetxattr(link string, attr string, dest []byte) (sz int, err error) {
+ return getxattr(link, attr, xattrPointer(dest), len(dest), 0, XATTR_NOFOLLOW)
+}
+
+//sys fgetxattr(fd int, attr string, dest *byte, size int, position uint32, options int) (sz int, err error)
+
+func Fgetxattr(fd int, attr string, dest []byte) (sz int, err error) {
+ return fgetxattr(fd, attr, xattrPointer(dest), len(dest), 0, 0)
+}
+
+//sys setxattr(path string, attr string, data *byte, size int, position uint32, options int) (err error)
+
+func Setxattr(path string, attr string, data []byte, flags int) (err error) {
+ // The parameters for the OS X implementation vary slightly compared to the
+ // linux system call, specifically the position parameter:
+ //
+ // linux:
+ // int setxattr(
+ // const char *path,
+ // const char *name,
+ // const void *value,
+ // size_t size,
+ // int flags
+ // );
+ //
+ // darwin:
+ // int setxattr(
+ // const char *path,
+ // const char *name,
+ // void *value,
+ // size_t size,
+ // u_int32_t position,
+ // int options
+ // );
+ //
+ // position specifies the offset within the extended attribute. In the
+ // current implementation, only the resource fork extended attribute makes
+ // use of this argument. For all others, position is reserved. We simply
+ // default to setting it to zero.
+ return setxattr(path, attr, xattrPointer(data), len(data), 0, flags)
+}
+
+func Lsetxattr(link string, attr string, data []byte, flags int) (err error) {
+ return setxattr(link, attr, xattrPointer(data), len(data), 0, flags|XATTR_NOFOLLOW)
+}
+
+//sys fsetxattr(fd int, attr string, data *byte, size int, position uint32, options int) (err error)
+
+func Fsetxattr(fd int, attr string, data []byte, flags int) (err error) {
+ return fsetxattr(fd, attr, xattrPointer(data), len(data), 0, 0)
+}
+
+//sys removexattr(path string, attr string, options int) (err error)
+
+func Removexattr(path string, attr string) (err error) {
+ // We wrap around and explicitly zero out the options provided to the OS X
+ // implementation of removexattr, we do so for interoperability with the
+ // linux variant.
+ return removexattr(path, attr, 0)
+}
+
+func Lremovexattr(link string, attr string) (err error) {
+ return removexattr(link, attr, XATTR_NOFOLLOW)
+}
+
+//sys fremovexattr(fd int, attr string, options int) (err error)
+
+func Fremovexattr(fd int, attr string) (err error) {
+ return fremovexattr(fd, attr, 0)
+}
+
+//sys listxattr(path string, dest *byte, size int, options int) (sz int, err error)
+
+func Listxattr(path string, dest []byte) (sz int, err error) {
+ return listxattr(path, xattrPointer(dest), len(dest), 0)
+}
+
+func Llistxattr(link string, dest []byte) (sz int, err error) {
+ return listxattr(link, xattrPointer(dest), len(dest), XATTR_NOFOLLOW)
+}
+
+//sys flistxattr(fd int, dest *byte, size int, options int) (sz int, err error)
+
+func Flistxattr(fd int, dest []byte) (sz int, err error) {
+ return flistxattr(fd, xattrPointer(dest), len(dest), 0)
+}
+
+func setattrlistTimes(path string, times []Timespec, flags int) error {
+ _p0, err := BytePtrFromString(path)
+ if err != nil {
+ return err
+ }
+
+ var attrList attrList
+ attrList.bitmapCount = ATTR_BIT_MAP_COUNT
+ attrList.CommonAttr = ATTR_CMN_MODTIME | ATTR_CMN_ACCTIME
+
+ // order is mtime, atime: the opposite of Chtimes
+ attributes := [2]Timespec{times[1], times[0]}
+ options := 0
+ if flags&AT_SYMLINK_NOFOLLOW != 0 {
+ options |= FSOPT_NOFOLLOW
+ }
+ return setattrlist(
+ _p0,
+ unsafe.Pointer(&attrList),
+ unsafe.Pointer(&attributes),
+ unsafe.Sizeof(attributes),
+ options)
+}
+
+//sys setattrlist(path *byte, list unsafe.Pointer, buf unsafe.Pointer, size uintptr, options int) (err error)
+
func utimensat(dirfd int, path string, times *[2]Timespec, flags int) error {
// Darwin doesn't support SYS_UTIMENSAT
return ENOSYS
@@ -196,48 +333,73 @@ func utimensat(dirfd int, path string, times *[2]Timespec, flags int) error {
* Wrapped
*/
+//sys fcntl(fd int, cmd int, arg int) (val int, err error)
+
//sys kill(pid int, signum int, posix int) (err error)
func Kill(pid int, signum syscall.Signal) (err error) { return kill(pid, int(signum), 1) }
//sys ioctl(fd int, req uint, arg uintptr) (err error)
-// ioctl itself should not be exposed directly, but additional get/set
-// functions for specific types are permissible.
+//sys sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) = SYS_SYSCTL
-// IoctlSetInt performs an ioctl operation which sets an integer value
-// on fd, using the specified request number.
-func IoctlSetInt(fd int, req uint, value int) error {
- return ioctl(fd, req, uintptr(value))
+func Uname(uname *Utsname) error {
+ mib := []_C_int{CTL_KERN, KERN_OSTYPE}
+ n := unsafe.Sizeof(uname.Sysname)
+ if err := sysctl(mib, &uname.Sysname[0], &n, nil, 0); err != nil {
+ return err
+ }
+
+ mib = []_C_int{CTL_KERN, KERN_HOSTNAME}
+ n = unsafe.Sizeof(uname.Nodename)
+ if err := sysctl(mib, &uname.Nodename[0], &n, nil, 0); err != nil {
+ return err
+ }
+
+ mib = []_C_int{CTL_KERN, KERN_OSRELEASE}
+ n = unsafe.Sizeof(uname.Release)
+ if err := sysctl(mib, &uname.Release[0], &n, nil, 0); err != nil {
+ return err
+ }
+
+ mib = []_C_int{CTL_KERN, KERN_VERSION}
+ n = unsafe.Sizeof(uname.Version)
+ if err := sysctl(mib, &uname.Version[0], &n, nil, 0); err != nil {
+ return err
+ }
+
+ // The version might have newlines or tabs in it, convert them to
+ // spaces.
+ for i, b := range uname.Version {
+ if b == '\n' || b == '\t' {
+ if i == len(uname.Version)-1 {
+ uname.Version[i] = 0
+ } else {
+ uname.Version[i] = ' '
+ }
+ }
+ }
+
+ mib = []_C_int{CTL_HW, HW_MACHINE}
+ n = unsafe.Sizeof(uname.Machine)
+ if err := sysctl(mib, &uname.Machine[0], &n, nil, 0); err != nil {
+ return err
+ }
+
+ return nil
}
-func IoctlSetWinsize(fd int, req uint, value *Winsize) error {
- return ioctl(fd, req, uintptr(unsafe.Pointer(value)))
+func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
+ if raceenabled {
+ raceReleaseMerge(unsafe.Pointer(&ioSync))
+ }
+ var length = int64(count)
+ err = sendfile(infd, outfd, *offset, &length, nil, 0)
+ written = int(length)
+ return
}
-func IoctlSetTermios(fd int, req uint, value *Termios) error {
- return ioctl(fd, req, uintptr(unsafe.Pointer(value)))
-}
-
-// IoctlGetInt performs an ioctl operation which gets an integer value
-// from fd, using the specified request number.
-func IoctlGetInt(fd int, req uint) (int, error) {
- var value int
- err := ioctl(fd, req, uintptr(unsafe.Pointer(&value)))
- return value, err
-}
-
-func IoctlGetWinsize(fd int, req uint) (*Winsize, error) {
- var value Winsize
- err := ioctl(fd, req, uintptr(unsafe.Pointer(&value)))
- return &value, err
-}
-
-func IoctlGetTermios(fd int, req uint) (*Termios, error) {
- var value Termios
- err := ioctl(fd, req, uintptr(unsafe.Pointer(&value)))
- return &value, err
-}
+//sys sendfile(infd int, outfd int, offset int64, len *int64, hdtr unsafe.Pointer, flags int) (err error)
/*
* Exposed directly
@@ -249,6 +411,7 @@ func IoctlGetTermios(fd int, req uint) (*Termios, error) {
//sys Chmod(path string, mode uint32) (err error)
//sys Chown(path string, uid int, gid int) (err error)
//sys Chroot(path string) (err error)
+//sys ClockGettime(clockid int32, time *Timespec) (err error)
//sys Close(fd int) (err error)
//sys Dup(fd int) (nfd int, err error)
//sys Dup2(from int, to int) (err error)
@@ -263,11 +426,8 @@ func IoctlGetTermios(fd int, req uint) (*Termios, error) {
//sys Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error)
//sys Flock(fd int, how int) (err error)
//sys Fpathconf(fd int, name int) (val int, err error)
-//sys Fstat(fd int, stat *Stat_t) (err error) = SYS_FSTAT64
-//sys Fstatfs(fd int, stat *Statfs_t) (err error) = SYS_FSTATFS64
//sys Fsync(fd int) (err error)
//sys Ftruncate(fd int, length int64) (err error)
-//sys Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) = SYS_GETDIRENTRIES64
//sys Getdtablesize() (size int)
//sysnb Getegid() (egid int)
//sysnb Geteuid() (uid int)
@@ -287,7 +447,6 @@ func IoctlGetTermios(fd int, req uint) (*Termios, error) {
//sys Link(path string, link string) (err error)
//sys Linkat(pathfd int, path string, linkfd int, link string, flags int) (err error)
//sys Listen(s int, backlog int) (err error)
-//sys Lstat(path string, stat *Stat_t) (err error) = SYS_LSTAT64
//sys Mkdir(path string, mode uint32) (err error)
//sys Mkdirat(dirfd int, path string, mode uint32) (err error)
//sys Mkfifo(path string, mode uint32) (err error)
@@ -305,7 +464,7 @@ func IoctlGetTermios(fd int, req uint) (*Termios, error) {
//sys Revoke(path string) (err error)
//sys Rmdir(path string) (err error)
//sys Seek(fd int, offset int64, whence int) (newoffset int64, err error) = SYS_LSEEK
-//sys Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error)
+//sys Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err error)
//sys Setegid(egid int) (err error)
//sysnb Seteuid(euid int) (err error)
//sysnb Setgid(gid int) (err error)
@@ -319,8 +478,6 @@ func IoctlGetTermios(fd int, req uint) (*Termios, error) {
//sysnb Setsid() (pid int, err error)
//sysnb Settimeofday(tp *Timeval) (err error)
//sysnb Setuid(uid int) (err error)
-//sys Stat(path string, stat *Stat_t) (err error) = SYS_STAT64
-//sys Statfs(path string, stat *Statfs_t) (err error) = SYS_STATFS64
//sys Symlink(path string, link string) (err error)
//sys Symlinkat(oldpath string, newdirfd int, newpath string) (err error)
//sys Sync() (err error)
@@ -377,18 +534,9 @@ func IoctlGetTermios(fd int, req uint) (*Termios, error) {
// Searchfs
// Delete
// Copyfile
-// Poll
// Watchevent
// Waitevent
// Modwatch
-// Getxattr
-// Fgetxattr
-// Setxattr
-// Fsetxattr
-// Removexattr
-// Fremovexattr
-// Listxattr
-// Flistxattr
// Fsctl
// Initgroups
// Posix_spawn
diff --git a/vendor/golang.org/x/sys/unix/syscall_darwin_386.1_11.go b/vendor/golang.org/x/sys/unix/syscall_darwin_386.1_11.go
new file mode 100644
index 0000000..6b223f9
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/syscall_darwin_386.1_11.go
@@ -0,0 +1,9 @@
+// Copyright 2019 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 darwin,386,!go1.12
+
+package unix
+
+//sys Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) = SYS_GETDIRENTRIES64
diff --git a/vendor/golang.org/x/sys/unix/syscall_darwin_386.go b/vendor/golang.org/x/sys/unix/syscall_darwin_386.go
index 76634f7..707ba4f 100644
--- a/vendor/golang.org/x/sys/unix/syscall_darwin_386.go
+++ b/vendor/golang.org/x/sys/unix/syscall_darwin_386.go
@@ -8,28 +8,22 @@ package unix
import (
"syscall"
- "unsafe"
)
-func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
+//sys ptrace(request int, pid int, addr uintptr, data uintptr) (err error)
-func NsecToTimespec(nsec int64) (ts Timespec) {
- ts.Sec = int32(nsec / 1e9)
- ts.Nsec = int32(nsec % 1e9)
- return
+func setTimespec(sec, nsec int64) Timespec {
+ return Timespec{Sec: int32(sec), Nsec: int32(nsec)}
}
-func NsecToTimeval(nsec int64) (tv Timeval) {
- nsec += 999 // round up to microsecond
- tv.Usec = int32(nsec % 1e9 / 1e3)
- tv.Sec = int32(nsec / 1e9)
- return
+func setTimeval(sec, usec int64) Timeval {
+ return Timeval{Sec: int32(sec), Usec: int32(usec)}
}
//sysnb gettimeofday(tp *Timeval) (sec int32, usec int32, err error)
func Gettimeofday(tv *Timeval) (err error) {
// The tv passed to gettimeofday must be non-nil
- // but is otherwise unused. The answers come back
+ // but is otherwise unused. The answers come back
// in the two registers.
sec, usec, err := gettimeofday(tv)
tv.Sec = int32(sec)
@@ -51,21 +45,12 @@ func (msghdr *Msghdr) SetControllen(length int) {
msghdr.Controllen = uint32(length)
}
-func (cmsg *Cmsghdr) SetLen(length int) {
- cmsg.Len = uint32(length)
+func (msghdr *Msghdr) SetIovlen(length int) {
+ msghdr.Iovlen = int32(length)
}
-func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
- var length = uint64(count)
-
- _, _, e1 := Syscall9(SYS_SENDFILE, uintptr(infd), uintptr(outfd), uintptr(*offset), uintptr(*offset>>32), uintptr(unsafe.Pointer(&length)), 0, 0, 0, 0)
-
- written = int(length)
-
- if e1 != 0 {
- err = e1
- }
- return
+func (cmsg *Cmsghdr) SetLen(length int) {
+ cmsg.Len = uint32(length)
}
func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno)
@@ -73,3 +58,11 @@ func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr,
// SYS___SYSCTL is used by syscall_bsd.go for all BSDs, but in modern versions
// of darwin/386 the syscall is called sysctl instead of __sysctl.
const SYS___SYSCTL = SYS_SYSCTL
+
+//sys Fstat(fd int, stat *Stat_t) (err error) = SYS_FSTAT64
+//sys Fstatat(fd int, path string, stat *Stat_t, flags int) (err error) = SYS_FSTATAT64
+//sys Fstatfs(fd int, stat *Statfs_t) (err error) = SYS_FSTATFS64
+//sys getfsstat(buf unsafe.Pointer, size uintptr, flags int) (n int, err error) = SYS_GETFSSTAT64
+//sys Lstat(path string, stat *Stat_t) (err error) = SYS_LSTAT64
+//sys Stat(path string, stat *Stat_t) (err error) = SYS_STAT64
+//sys Statfs(path string, stat *Statfs_t) (err error) = SYS_STATFS64
diff --git a/vendor/golang.org/x/sys/unix/syscall_darwin_amd64.1_11.go b/vendor/golang.org/x/sys/unix/syscall_darwin_amd64.1_11.go
new file mode 100644
index 0000000..68ebd6f
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/syscall_darwin_amd64.1_11.go
@@ -0,0 +1,9 @@
+// Copyright 2019 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 darwin,amd64,!go1.12
+
+package unix
+
+//sys Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) = SYS_GETDIRENTRIES64
diff --git a/vendor/golang.org/x/sys/unix/syscall_darwin_amd64.go b/vendor/golang.org/x/sys/unix/syscall_darwin_amd64.go
index 7be02da..fdbfb59 100644
--- a/vendor/golang.org/x/sys/unix/syscall_darwin_amd64.go
+++ b/vendor/golang.org/x/sys/unix/syscall_darwin_amd64.go
@@ -8,28 +8,22 @@ package unix
import (
"syscall"
- "unsafe"
)
-func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
+//sys ptrace(request int, pid int, addr uintptr, data uintptr) (err error)
-func NsecToTimespec(nsec int64) (ts Timespec) {
- ts.Sec = nsec / 1e9
- ts.Nsec = nsec % 1e9
- return
+func setTimespec(sec, nsec int64) Timespec {
+ return Timespec{Sec: sec, Nsec: nsec}
}
-func NsecToTimeval(nsec int64) (tv Timeval) {
- nsec += 999 // round up to microsecond
- tv.Usec = int32(nsec % 1e9 / 1e3)
- tv.Sec = int64(nsec / 1e9)
- return
+func setTimeval(sec, usec int64) Timeval {
+ return Timeval{Sec: sec, Usec: int32(usec)}
}
//sysnb gettimeofday(tp *Timeval) (sec int64, usec int32, err error)
func Gettimeofday(tv *Timeval) (err error) {
// The tv passed to gettimeofday must be non-nil
- // but is otherwise unused. The answers come back
+ // but is otherwise unused. The answers come back
// in the two registers.
sec, usec, err := gettimeofday(tv)
tv.Sec = sec
@@ -51,21 +45,12 @@ func (msghdr *Msghdr) SetControllen(length int) {
msghdr.Controllen = uint32(length)
}
-func (cmsg *Cmsghdr) SetLen(length int) {
- cmsg.Len = uint32(length)
+func (msghdr *Msghdr) SetIovlen(length int) {
+ msghdr.Iovlen = int32(length)
}
-func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
- var length = uint64(count)
-
- _, _, e1 := Syscall6(SYS_SENDFILE, uintptr(infd), uintptr(outfd), uintptr(*offset), uintptr(unsafe.Pointer(&length)), 0, 0)
-
- written = int(length)
-
- if e1 != 0 {
- err = e1
- }
- return
+func (cmsg *Cmsghdr) SetLen(length int) {
+ cmsg.Len = uint32(length)
}
func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno)
@@ -73,3 +58,11 @@ func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr,
// SYS___SYSCTL is used by syscall_bsd.go for all BSDs, but in modern versions
// of darwin/amd64 the syscall is called sysctl instead of __sysctl.
const SYS___SYSCTL = SYS_SYSCTL
+
+//sys Fstat(fd int, stat *Stat_t) (err error) = SYS_FSTAT64
+//sys Fstatat(fd int, path string, stat *Stat_t, flags int) (err error) = SYS_FSTATAT64
+//sys Fstatfs(fd int, stat *Statfs_t) (err error) = SYS_FSTATFS64
+//sys getfsstat(buf unsafe.Pointer, size uintptr, flags int) (n int, err error) = SYS_GETFSSTAT64
+//sys Lstat(path string, stat *Stat_t) (err error) = SYS_LSTAT64
+//sys Stat(path string, stat *Stat_t) (err error) = SYS_STAT64
+//sys Statfs(path string, stat *Statfs_t) (err error) = SYS_STATFS64
diff --git a/vendor/golang.org/x/sys/unix/syscall_darwin_arm.1_11.go b/vendor/golang.org/x/sys/unix/syscall_darwin_arm.1_11.go
new file mode 100644
index 0000000..0e3f25a
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/syscall_darwin_arm.1_11.go
@@ -0,0 +1,11 @@
+// Copyright 2019 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 darwin,arm,!go1.12
+
+package unix
+
+func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
+ return 0, ENOSYS
+}
diff --git a/vendor/golang.org/x/sys/unix/syscall_darwin_arm.go b/vendor/golang.org/x/sys/unix/syscall_darwin_arm.go
index 26b6697..f8bc4cf 100644
--- a/vendor/golang.org/x/sys/unix/syscall_darwin_arm.go
+++ b/vendor/golang.org/x/sys/unix/syscall_darwin_arm.go
@@ -6,28 +6,24 @@ package unix
import (
"syscall"
- "unsafe"
)
-func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
-
-func NsecToTimespec(nsec int64) (ts Timespec) {
- ts.Sec = int32(nsec / 1e9)
- ts.Nsec = int32(nsec % 1e9)
- return
+func ptrace(request int, pid int, addr uintptr, data uintptr) error {
+ return ENOTSUP
}
-func NsecToTimeval(nsec int64) (tv Timeval) {
- nsec += 999 // round up to microsecond
- tv.Usec = int32(nsec % 1e9 / 1e3)
- tv.Sec = int32(nsec / 1e9)
- return
+func setTimespec(sec, nsec int64) Timespec {
+ return Timespec{Sec: int32(sec), Nsec: int32(nsec)}
+}
+
+func setTimeval(sec, usec int64) Timeval {
+ return Timeval{Sec: int32(sec), Usec: int32(usec)}
}
//sysnb gettimeofday(tp *Timeval) (sec int32, usec int32, err error)
func Gettimeofday(tv *Timeval) (err error) {
// The tv passed to gettimeofday must be non-nil
- // but is otherwise unused. The answers come back
+ // but is otherwise unused. The answers come back
// in the two registers.
sec, usec, err := gettimeofday(tv)
tv.Sec = int32(sec)
@@ -49,21 +45,24 @@ func (msghdr *Msghdr) SetControllen(length int) {
msghdr.Controllen = uint32(length)
}
+func (msghdr *Msghdr) SetIovlen(length int) {
+ msghdr.Iovlen = int32(length)
+}
+
func (cmsg *Cmsghdr) SetLen(length int) {
cmsg.Len = uint32(length)
}
-func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
- var length = uint64(count)
-
- _, _, e1 := Syscall9(SYS_SENDFILE, uintptr(infd), uintptr(outfd), uintptr(*offset), uintptr(*offset>>32), uintptr(unsafe.Pointer(&length)), 0, 0, 0, 0)
-
- written = int(length)
-
- if e1 != 0 {
- err = e1
- }
- return
-}
-
func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno) // sic
+
+// SYS___SYSCTL is used by syscall_bsd.go for all BSDs, but in modern versions
+// of darwin/arm the syscall is called sysctl instead of __sysctl.
+const SYS___SYSCTL = SYS_SYSCTL
+
+//sys Fstat(fd int, stat *Stat_t) (err error)
+//sys Fstatat(fd int, path string, stat *Stat_t, flags int) (err error)
+//sys Fstatfs(fd int, stat *Statfs_t) (err error)
+//sys getfsstat(buf unsafe.Pointer, size uintptr, flags int) (n int, err error) = SYS_GETFSSTAT
+//sys Lstat(path string, stat *Stat_t) (err error)
+//sys Stat(path string, stat *Stat_t) (err error)
+//sys Statfs(path string, stat *Statfs_t) (err error)
diff --git a/vendor/golang.org/x/sys/unix/syscall_darwin_arm64.1_11.go b/vendor/golang.org/x/sys/unix/syscall_darwin_arm64.1_11.go
new file mode 100644
index 0000000..01d4504
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/syscall_darwin_arm64.1_11.go
@@ -0,0 +1,11 @@
+// Copyright 2019 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 darwin,arm64,!go1.12
+
+package unix
+
+func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
+ return 0, ENOSYS
+}
diff --git a/vendor/golang.org/x/sys/unix/syscall_darwin_arm64.go b/vendor/golang.org/x/sys/unix/syscall_darwin_arm64.go
index 4d67a87..5ede3ac 100644
--- a/vendor/golang.org/x/sys/unix/syscall_darwin_arm64.go
+++ b/vendor/golang.org/x/sys/unix/syscall_darwin_arm64.go
@@ -8,28 +8,24 @@ package unix
import (
"syscall"
- "unsafe"
)
-func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
-
-func NsecToTimespec(nsec int64) (ts Timespec) {
- ts.Sec = nsec / 1e9
- ts.Nsec = nsec % 1e9
- return
+func ptrace(request int, pid int, addr uintptr, data uintptr) error {
+ return ENOTSUP
}
-func NsecToTimeval(nsec int64) (tv Timeval) {
- nsec += 999 // round up to microsecond
- tv.Usec = int32(nsec % 1e9 / 1e3)
- tv.Sec = int64(nsec / 1e9)
- return
+func setTimespec(sec, nsec int64) Timespec {
+ return Timespec{Sec: sec, Nsec: nsec}
+}
+
+func setTimeval(sec, usec int64) Timeval {
+ return Timeval{Sec: sec, Usec: int32(usec)}
}
//sysnb gettimeofday(tp *Timeval) (sec int64, usec int32, err error)
func Gettimeofday(tv *Timeval) (err error) {
// The tv passed to gettimeofday must be non-nil
- // but is otherwise unused. The answers come back
+ // but is otherwise unused. The answers come back
// in the two registers.
sec, usec, err := gettimeofday(tv)
tv.Sec = sec
@@ -51,21 +47,12 @@ func (msghdr *Msghdr) SetControllen(length int) {
msghdr.Controllen = uint32(length)
}
-func (cmsg *Cmsghdr) SetLen(length int) {
- cmsg.Len = uint32(length)
+func (msghdr *Msghdr) SetIovlen(length int) {
+ msghdr.Iovlen = int32(length)
}
-func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
- var length = uint64(count)
-
- _, _, e1 := Syscall6(SYS_SENDFILE, uintptr(infd), uintptr(outfd), uintptr(*offset), uintptr(unsafe.Pointer(&length)), 0, 0)
-
- written = int(length)
-
- if e1 != 0 {
- err = e1
- }
- return
+func (cmsg *Cmsghdr) SetLen(length int) {
+ cmsg.Len = uint32(length)
}
func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno) // sic
@@ -73,3 +60,11 @@ func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr,
// SYS___SYSCTL is used by syscall_bsd.go for all BSDs, but in modern versions
// of darwin/arm64 the syscall is called sysctl instead of __sysctl.
const SYS___SYSCTL = SYS_SYSCTL
+
+//sys Fstat(fd int, stat *Stat_t) (err error)
+//sys Fstatat(fd int, path string, stat *Stat_t, flags int) (err error)
+//sys Fstatfs(fd int, stat *Statfs_t) (err error)
+//sys getfsstat(buf unsafe.Pointer, size uintptr, flags int) (n int, err error) = SYS_GETFSSTAT
+//sys Lstat(path string, stat *Stat_t) (err error)
+//sys Stat(path string, stat *Stat_t) (err error)
+//sys Statfs(path string, stat *Statfs_t) (err error)
diff --git a/vendor/golang.org/x/sys/unix/syscall_darwin_libSystem.go b/vendor/golang.org/x/sys/unix/syscall_darwin_libSystem.go
new file mode 100644
index 0000000..f34c86c
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/syscall_darwin_libSystem.go
@@ -0,0 +1,33 @@
+// Copyright 2018 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 darwin,go1.12
+
+package unix
+
+import "unsafe"
+
+// Implemented in the runtime package (runtime/sys_darwin.go)
+func syscall_syscall(fn, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)
+func syscall_syscall6(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
+func syscall_syscall6X(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
+func syscall_syscall9(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno) // 32-bit only
+func syscall_rawSyscall(fn, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)
+func syscall_rawSyscall6(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
+func syscall_syscallPtr(fn, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)
+
+//go:linkname syscall_syscall syscall.syscall
+//go:linkname syscall_syscall6 syscall.syscall6
+//go:linkname syscall_syscall6X syscall.syscall6X
+//go:linkname syscall_syscall9 syscall.syscall9
+//go:linkname syscall_rawSyscall syscall.rawSyscall
+//go:linkname syscall_rawSyscall6 syscall.rawSyscall6
+//go:linkname syscall_syscallPtr syscall.syscallPtr
+
+// Find the entry point for f. See comments in runtime/proc.go for the
+// function of the same name.
+//go:nosplit
+func funcPC(f func()) uintptr {
+ return **(**uintptr)(unsafe.Pointer(&f))
+}
diff --git a/vendor/golang.org/x/sys/unix/syscall_dragonfly.go b/vendor/golang.org/x/sys/unix/syscall_dragonfly.go
index 3a48337..8a195ae 100644
--- a/vendor/golang.org/x/sys/unix/syscall_dragonfly.go
+++ b/vendor/golang.org/x/sys/unix/syscall_dragonfly.go
@@ -12,8 +12,27 @@
package unix
-import "unsafe"
+import (
+ "sync"
+ "unsafe"
+)
+// See version list in https://github.com/DragonFlyBSD/DragonFlyBSD/blob/master/sys/sys/param.h
+var (
+ osreldateOnce sync.Once
+ osreldate uint32
+)
+
+// First __DragonFly_version after September 2019 ABI changes
+// http://lists.dragonflybsd.org/pipermail/users/2019-September/358280.html
+const _dragonflyABIChangeVersion = 500705
+
+func supportsABI(ver uint32) bool {
+ osreldateOnce.Do(func() { osreldate, _ = SysctlUint32("kern.osreldate") })
+ return osreldate >= ver
+}
+
+// SockaddrDatalink implements the Sockaddr interface for AF_LINK type sockets.
type SockaddrDatalink struct {
Len uint8
Family uint8
@@ -102,7 +121,7 @@ func Accept4(fd, flags int) (nfd int, sa Sockaddr, err error) {
if len > SizeofSockaddrAny {
panic("RawSockaddrAny too small")
}
- sa, err = anyToSockaddr(&rsa)
+ sa, err = anyToSockaddr(fd, &rsa)
if err != nil {
Close(nfd)
nfd = 0
@@ -110,6 +129,23 @@ func Accept4(fd, flags int) (nfd int, sa Sockaddr, err error) {
return
}
+const ImplementsGetwd = true
+
+//sys Getcwd(buf []byte) (n int, err error) = SYS___GETCWD
+
+func Getwd() (string, error) {
+ var buf [PathMax]byte
+ _, err := Getcwd(buf[0:])
+ if err != nil {
+ return "", err
+ }
+ n := clen(buf[:])
+ if n < 1 {
+ return "", EINVAL
+ }
+ return string(buf[:n]), nil
+}
+
func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
var _p0 unsafe.Pointer
var bufsize uintptr
@@ -125,6 +161,85 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
return
}
+func setattrlistTimes(path string, times []Timespec, flags int) error {
+ // used on Darwin for UtimesNano
+ return ENOSYS
+}
+
+//sys ioctl(fd int, req uint, arg uintptr) (err error)
+
+//sys sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) = SYS___SYSCTL
+
+func sysctlUname(mib []_C_int, old *byte, oldlen *uintptr) error {
+ err := sysctl(mib, old, oldlen, nil, 0)
+ if err != nil {
+ // Utsname members on Dragonfly are only 32 bytes and
+ // the syscall returns ENOMEM in case the actual value
+ // is longer.
+ if err == ENOMEM {
+ err = nil
+ }
+ }
+ return err
+}
+
+func Uname(uname *Utsname) error {
+ mib := []_C_int{CTL_KERN, KERN_OSTYPE}
+ n := unsafe.Sizeof(uname.Sysname)
+ if err := sysctlUname(mib, &uname.Sysname[0], &n); err != nil {
+ return err
+ }
+ uname.Sysname[unsafe.Sizeof(uname.Sysname)-1] = 0
+
+ mib = []_C_int{CTL_KERN, KERN_HOSTNAME}
+ n = unsafe.Sizeof(uname.Nodename)
+ if err := sysctlUname(mib, &uname.Nodename[0], &n); err != nil {
+ return err
+ }
+ uname.Nodename[unsafe.Sizeof(uname.Nodename)-1] = 0
+
+ mib = []_C_int{CTL_KERN, KERN_OSRELEASE}
+ n = unsafe.Sizeof(uname.Release)
+ if err := sysctlUname(mib, &uname.Release[0], &n); err != nil {
+ return err
+ }
+ uname.Release[unsafe.Sizeof(uname.Release)-1] = 0
+
+ mib = []_C_int{CTL_KERN, KERN_VERSION}
+ n = unsafe.Sizeof(uname.Version)
+ if err := sysctlUname(mib, &uname.Version[0], &n); err != nil {
+ return err
+ }
+
+ // The version might have newlines or tabs in it, convert them to
+ // spaces.
+ for i, b := range uname.Version {
+ if b == '\n' || b == '\t' {
+ if i == len(uname.Version)-1 {
+ uname.Version[i] = 0
+ } else {
+ uname.Version[i] = ' '
+ }
+ }
+ }
+
+ mib = []_C_int{CTL_HW, HW_MACHINE}
+ n = unsafe.Sizeof(uname.Machine)
+ if err := sysctlUname(mib, &uname.Machine[0], &n); err != nil {
+ return err
+ }
+ uname.Machine[unsafe.Sizeof(uname.Machine)-1] = 0
+
+ return nil
+}
+
+func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
+ if raceenabled {
+ raceReleaseMerge(unsafe.Pointer(&ioSync))
+ }
+ return sendfile(outfd, infd, offset, count)
+}
+
/*
* Exposed directly
*/
@@ -139,16 +254,21 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
//sys Dup(fd int) (nfd int, err error)
//sys Dup2(from int, to int) (err error)
//sys Exit(code int)
+//sys Faccessat(dirfd int, path string, mode uint32, flags int) (err error)
//sys Fchdir(fd int) (err error)
//sys Fchflags(fd int, flags int) (err error)
//sys Fchmod(fd int, mode uint32) (err error)
+//sys Fchmodat(dirfd int, path string, mode uint32, flags int) (err error)
//sys Fchown(fd int, uid int, gid int) (err error)
+//sys Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error)
//sys Flock(fd int, how int) (err error)
//sys Fpathconf(fd int, name int) (val int, err error)
//sys Fstat(fd int, stat *Stat_t) (err error)
+//sys Fstatat(fd int, path string, stat *Stat_t, flags int) (err error)
//sys Fstatfs(fd int, stat *Statfs_t) (err error)
//sys Fsync(fd int) (err error)
//sys Ftruncate(fd int, length int64) (err error)
+//sys Getdents(fd int, buf []byte) (n int, err error)
//sys Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error)
//sys Getdtablesize() (size int)
//sysnb Getegid() (egid int)
@@ -169,21 +289,26 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
//sys Kqueue() (fd int, err error)
//sys Lchown(path string, uid int, gid int) (err error)
//sys Link(path string, link string) (err error)
+//sys Linkat(pathfd int, path string, linkfd int, link string, flags int) (err error)
//sys Listen(s int, backlog int) (err error)
//sys Lstat(path string, stat *Stat_t) (err error)
//sys Mkdir(path string, mode uint32) (err error)
+//sys Mkdirat(dirfd int, path string, mode uint32) (err error)
//sys Mkfifo(path string, mode uint32) (err error)
//sys Mknod(path string, mode uint32, dev int) (err error)
+//sys Mknodat(fd int, path string, mode uint32, dev int) (err error)
//sys Nanosleep(time *Timespec, leftover *Timespec) (err error)
//sys Open(path string, mode int, perm uint32) (fd int, err error)
+//sys Openat(dirfd int, path string, mode int, perm uint32) (fd int, err error)
//sys Pathconf(path string, name int) (val int, err error)
//sys read(fd int, p []byte) (n int, err error)
//sys Readlink(path string, buf []byte) (n int, err error)
//sys Rename(from string, to string) (err error)
+//sys Renameat(fromfd int, from string, tofd int, to string) (err error)
//sys Revoke(path string) (err error)
//sys Rmdir(path string) (err error)
//sys Seek(fd int, offset int64, whence int) (newoffset int64, err error) = SYS_LSEEK
-//sys Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error)
+//sys Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err error)
//sysnb Setegid(egid int) (err error)
//sysnb Seteuid(euid int) (err error)
//sysnb Setgid(gid int) (err error)
@@ -201,11 +326,13 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
//sys Stat(path string, stat *Stat_t) (err error)
//sys Statfs(path string, stat *Statfs_t) (err error)
//sys Symlink(path string, link string) (err error)
+//sys Symlinkat(oldpath string, newdirfd int, newpath string) (err error)
//sys Sync() (err error)
//sys Truncate(path string, length int64) (err error)
//sys Umask(newmask int) (oldmask int)
//sys Undelete(path string) (err error)
//sys Unlink(path string) (err error)
+//sys Unlinkat(dirfd int, path string, flags int) (err error)
//sys Unmount(path string, flags int) (err error)
//sys write(fd int, p []byte) (n int, err error)
//sys mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error)
@@ -225,7 +352,6 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
// Getlogin
// Sigpending
// Sigaltstack
-// Ioctl
// Reboot
// Execve
// Vfork
@@ -257,7 +383,6 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
// Searchfs
// Delete
// Copyfile
-// Poll
// Watchevent
// Waitevent
// Modwatch
@@ -403,7 +528,6 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
// Pread_nocancel
// Pwrite_nocancel
// Waitid_nocancel
-// Poll_nocancel
// Msgsnd_nocancel
// Msgrcv_nocancel
// Sem_wait_nocancel
diff --git a/vendor/golang.org/x/sys/unix/syscall_dragonfly_amd64.go b/vendor/golang.org/x/sys/unix/syscall_dragonfly_amd64.go
index 6d8952d..a6b4830 100644
--- a/vendor/golang.org/x/sys/unix/syscall_dragonfly_amd64.go
+++ b/vendor/golang.org/x/sys/unix/syscall_dragonfly_amd64.go
@@ -11,19 +11,12 @@ import (
"unsafe"
)
-func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
-
-func NsecToTimespec(nsec int64) (ts Timespec) {
- ts.Sec = nsec / 1e9
- ts.Nsec = nsec % 1e9
- return
+func setTimespec(sec, nsec int64) Timespec {
+ return Timespec{Sec: sec, Nsec: nsec}
}
-func NsecToTimeval(nsec int64) (tv Timeval) {
- nsec += 999 // round up to microsecond
- tv.Usec = nsec % 1e9 / 1e3
- tv.Sec = int64(nsec / 1e9)
- return
+func setTimeval(sec, usec int64) Timeval {
+ return Timeval{Sec: sec, Usec: usec}
}
func SetKevent(k *Kevent_t, fd, mode, flags int) {
@@ -40,6 +33,10 @@ func (msghdr *Msghdr) SetControllen(length int) {
msghdr.Controllen = uint32(length)
}
+func (msghdr *Msghdr) SetIovlen(length int) {
+ msghdr.Iovlen = int32(length)
+}
+
func (cmsg *Cmsghdr) SetLen(length int) {
cmsg.Len = uint32(length)
}
diff --git a/vendor/golang.org/x/sys/unix/syscall_freebsd.go b/vendor/golang.org/x/sys/unix/syscall_freebsd.go
index d26e52e..34918d8 100644
--- a/vendor/golang.org/x/sys/unix/syscall_freebsd.go
+++ b/vendor/golang.org/x/sys/unix/syscall_freebsd.go
@@ -12,8 +12,36 @@
package unix
-import "unsafe"
+import (
+ "sync"
+ "unsafe"
+)
+const (
+ SYS_FSTAT_FREEBSD12 = 551 // { int fstat(int fd, _Out_ struct stat *sb); }
+ SYS_FSTATAT_FREEBSD12 = 552 // { int fstatat(int fd, _In_z_ char *path, \
+ SYS_GETDIRENTRIES_FREEBSD12 = 554 // { ssize_t getdirentries(int fd, \
+ SYS_STATFS_FREEBSD12 = 555 // { int statfs(_In_z_ char *path, \
+ SYS_FSTATFS_FREEBSD12 = 556 // { int fstatfs(int fd, \
+ SYS_GETFSSTAT_FREEBSD12 = 557 // { int getfsstat( \
+ SYS_MKNODAT_FREEBSD12 = 559 // { int mknodat(int fd, _In_z_ char *path, \
+)
+
+// See https://www.freebsd.org/doc/en_US.ISO8859-1/books/porters-handbook/versions.html.
+var (
+ osreldateOnce sync.Once
+ osreldate uint32
+)
+
+// INO64_FIRST from /usr/src/lib/libc/sys/compat-ino64.h
+const _ino64First = 1200031
+
+func supportsABI(ver uint32) bool {
+ osreldateOnce.Do(func() { osreldate, _ = SysctlUint32("kern.osreldate") })
+ return osreldate >= ver
+}
+
+// SockaddrDatalink implements the Sockaddr interface for AF_LINK type sockets.
type SockaddrDatalink struct {
Len uint8
Family uint8
@@ -32,7 +60,7 @@ func nametomib(name string) (mib []_C_int, err error) {
// NOTE(rsc): It seems strange to set the buffer to have
// size CTL_MAXNAME+2 but use only CTL_MAXNAME
- // as the size. I don't know why the +2 is here, but the
+ // as the size. I don't know why the +2 is here, but the
// kernel uses +2 for its own implementation of this function.
// I am scared that if we don't include the +2 here, the kernel
// will silently write 2 words farther than we specify
@@ -66,14 +94,21 @@ func direntNamlen(buf []byte) (uint64, bool) {
return readInt(buf, unsafe.Offsetof(Dirent{}.Namlen), unsafe.Sizeof(Dirent{}.Namlen))
}
-//sysnb pipe() (r int, w int, err error)
-
func Pipe(p []int) (err error) {
+ return Pipe2(p, 0)
+}
+
+//sysnb pipe2(p *[2]_C_int, flags int) (err error)
+
+func Pipe2(p []int, flags int) error {
if len(p) != 2 {
return EINVAL
}
- p[0], p[1], err = pipe()
- return
+ var pp [2]_C_int
+ err := pipe2(&pp, flags)
+ p[0] = int(pp[0])
+ p[1] = int(pp[1])
+ return err
}
func GetsockoptIPMreqn(fd, level, opt int) (*IPMreqn, error) {
@@ -97,7 +132,7 @@ func Accept4(fd, flags int) (nfd int, sa Sockaddr, err error) {
if len > SizeofSockaddrAny {
panic("RawSockaddrAny too small")
}
- sa, err = anyToSockaddr(&rsa)
+ sa, err = anyToSockaddr(fd, &rsa)
if err != nil {
Close(nfd)
nfd = 0
@@ -105,290 +140,431 @@ func Accept4(fd, flags int) (nfd int, sa Sockaddr, err error) {
return
}
-func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
- var _p0 unsafe.Pointer
- var bufsize uintptr
- if len(buf) > 0 {
- _p0 = unsafe.Pointer(&buf[0])
- bufsize = unsafe.Sizeof(Statfs_t{}) * uintptr(len(buf))
+const ImplementsGetwd = true
+
+//sys Getcwd(buf []byte) (n int, err error) = SYS___GETCWD
+
+func Getwd() (string, error) {
+ var buf [PathMax]byte
+ _, err := Getcwd(buf[0:])
+ if err != nil {
+ return "", err
}
- r0, _, e1 := Syscall(SYS_GETFSSTAT, uintptr(_p0), bufsize, uintptr(flags))
+ n := clen(buf[:])
+ if n < 1 {
+ return "", EINVAL
+ }
+ return string(buf[:n]), nil
+}
+
+func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
+ var (
+ _p0 unsafe.Pointer
+ bufsize uintptr
+ oldBuf []statfs_freebsd11_t
+ needsConvert bool
+ )
+
+ if len(buf) > 0 {
+ if supportsABI(_ino64First) {
+ _p0 = unsafe.Pointer(&buf[0])
+ bufsize = unsafe.Sizeof(Statfs_t{}) * uintptr(len(buf))
+ } else {
+ n := len(buf)
+ oldBuf = make([]statfs_freebsd11_t, n)
+ _p0 = unsafe.Pointer(&oldBuf[0])
+ bufsize = unsafe.Sizeof(statfs_freebsd11_t{}) * uintptr(n)
+ needsConvert = true
+ }
+ }
+ var sysno uintptr = SYS_GETFSSTAT
+ if supportsABI(_ino64First) {
+ sysno = SYS_GETFSSTAT_FREEBSD12
+ }
+ r0, _, e1 := Syscall(sysno, uintptr(_p0), bufsize, uintptr(flags))
n = int(r0)
if e1 != 0 {
err = e1
}
+ if e1 == 0 && needsConvert {
+ for i := range oldBuf {
+ buf[i].convertFrom(&oldBuf[i])
+ }
+ }
return
}
-// Derive extattr namespace and attribute name
-
-func xattrnamespace(fullattr string) (ns int, attr string, err error) {
- s := -1
- for idx, val := range fullattr {
- if val == '.' {
- s = idx
- break
- }
- }
-
- if s == -1 {
- return -1, "", ENOATTR
- }
-
- namespace := fullattr[0:s]
- attr = fullattr[s+1:]
-
- switch namespace {
- case "user":
- return EXTATTR_NAMESPACE_USER, attr, nil
- case "system":
- return EXTATTR_NAMESPACE_SYSTEM, attr, nil
- default:
- return -1, "", ENOATTR
- }
-}
-
-func initxattrdest(dest []byte, idx int) (d unsafe.Pointer) {
- if len(dest) > idx {
- return unsafe.Pointer(&dest[idx])
- } else {
- return unsafe.Pointer(_zero)
- }
-}
-
-// FreeBSD implements its own syscalls to handle extended attributes
-
-func Getxattr(file string, attr string, dest []byte) (sz int, err error) {
- d := initxattrdest(dest, 0)
- destsize := len(dest)
-
- nsid, a, err := xattrnamespace(attr)
- if err != nil {
- return -1, err
- }
-
- return ExtattrGetFile(file, nsid, a, uintptr(d), destsize)
-}
-
-func Fgetxattr(fd int, attr string, dest []byte) (sz int, err error) {
- d := initxattrdest(dest, 0)
- destsize := len(dest)
-
- nsid, a, err := xattrnamespace(attr)
- if err != nil {
- return -1, err
- }
-
- return ExtattrGetFd(fd, nsid, a, uintptr(d), destsize)
-}
-
-func Lgetxattr(link string, attr string, dest []byte) (sz int, err error) {
- d := initxattrdest(dest, 0)
- destsize := len(dest)
-
- nsid, a, err := xattrnamespace(attr)
- if err != nil {
- return -1, err
- }
-
- return ExtattrGetLink(link, nsid, a, uintptr(d), destsize)
-}
-
-// flags are unused on FreeBSD
-
-func Fsetxattr(fd int, attr string, data []byte, flags int) (err error) {
- d := unsafe.Pointer(&data[0])
- datasiz := len(data)
-
- nsid, a, err := xattrnamespace(attr)
- if err != nil {
- return
- }
-
- _, err = ExtattrSetFd(fd, nsid, a, uintptr(d), datasiz)
- return
-}
-
-func Setxattr(file string, attr string, data []byte, flags int) (err error) {
- d := unsafe.Pointer(&data[0])
- datasiz := len(data)
-
- nsid, a, err := xattrnamespace(attr)
- if err != nil {
- return
- }
-
- _, err = ExtattrSetFile(file, nsid, a, uintptr(d), datasiz)
- return
-}
-
-func Lsetxattr(link string, attr string, data []byte, flags int) (err error) {
- d := unsafe.Pointer(&data[0])
- datasiz := len(data)
-
- nsid, a, err := xattrnamespace(attr)
- if err != nil {
- return
- }
-
- _, err = ExtattrSetLink(link, nsid, a, uintptr(d), datasiz)
- return
-}
-
-func Removexattr(file string, attr string) (err error) {
- nsid, a, err := xattrnamespace(attr)
- if err != nil {
- return
- }
-
- err = ExtattrDeleteFile(file, nsid, a)
- return
-}
-
-func Fremovexattr(fd int, attr string) (err error) {
- nsid, a, err := xattrnamespace(attr)
- if err != nil {
- return
- }
-
- err = ExtattrDeleteFd(fd, nsid, a)
- return
-}
-
-func Lremovexattr(link string, attr string) (err error) {
- nsid, a, err := xattrnamespace(attr)
- if err != nil {
- return
- }
-
- err = ExtattrDeleteLink(link, nsid, a)
- return
-}
-
-func Listxattr(file string, dest []byte) (sz int, err error) {
- d := initxattrdest(dest, 0)
- destsiz := len(dest)
-
- // FreeBSD won't allow you to list xattrs from multiple namespaces
- s := 0
- var e error
- for _, nsid := range [...]int{EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM} {
- stmp, e := ExtattrListFile(file, nsid, uintptr(d), destsiz)
-
- /* Errors accessing system attrs are ignored so that
- * we can implement the Linux-like behavior of omitting errors that
- * we don't have read permissions on
- *
- * Linux will still error if we ask for user attributes on a file that
- * we don't have read permissions on, so don't ignore those errors
- */
- if e != nil && e == EPERM && nsid != EXTATTR_NAMESPACE_USER {
- e = nil
- continue
- } else if e != nil {
- return s, e
- }
-
- s += stmp
- destsiz -= s
- if destsiz < 0 {
- destsiz = 0
- }
- d = initxattrdest(dest, s)
- }
-
- return s, e
-}
-
-func Flistxattr(fd int, dest []byte) (sz int, err error) {
- d := initxattrdest(dest, 0)
- destsiz := len(dest)
-
- s := 0
- var e error
- for _, nsid := range [...]int{EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM} {
- stmp, e := ExtattrListFd(fd, nsid, uintptr(d), destsiz)
- if e != nil && e == EPERM && nsid != EXTATTR_NAMESPACE_USER {
- e = nil
- continue
- } else if e != nil {
- return s, e
- }
-
- s += stmp
- destsiz -= s
- if destsiz < 0 {
- destsiz = 0
- }
- d = initxattrdest(dest, s)
- }
-
- return s, e
-}
-
-func Llistxattr(link string, dest []byte) (sz int, err error) {
- d := initxattrdest(dest, 0)
- destsiz := len(dest)
-
- s := 0
- var e error
- for _, nsid := range [...]int{EXTATTR_NAMESPACE_USER, EXTATTR_NAMESPACE_SYSTEM} {
- stmp, e := ExtattrListLink(link, nsid, uintptr(d), destsiz)
- if e != nil && e == EPERM && nsid != EXTATTR_NAMESPACE_USER {
- e = nil
- continue
- } else if e != nil {
- return s, e
- }
-
- s += stmp
- destsiz -= s
- if destsiz < 0 {
- destsiz = 0
- }
- d = initxattrdest(dest, s)
- }
-
- return s, e
+func setattrlistTimes(path string, times []Timespec, flags int) error {
+ // used on Darwin for UtimesNano
+ return ENOSYS
}
//sys ioctl(fd int, req uint, arg uintptr) (err error)
-// ioctl itself should not be exposed directly, but additional get/set
-// functions for specific types are permissible.
+//sys sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) = SYS___SYSCTL
-// IoctlSetInt performs an ioctl operation which sets an integer value
-// on fd, using the specified request number.
-func IoctlSetInt(fd int, req uint, value int) error {
- return ioctl(fd, req, uintptr(value))
+func Uname(uname *Utsname) error {
+ mib := []_C_int{CTL_KERN, KERN_OSTYPE}
+ n := unsafe.Sizeof(uname.Sysname)
+ if err := sysctl(mib, &uname.Sysname[0], &n, nil, 0); err != nil {
+ return err
+ }
+
+ mib = []_C_int{CTL_KERN, KERN_HOSTNAME}
+ n = unsafe.Sizeof(uname.Nodename)
+ if err := sysctl(mib, &uname.Nodename[0], &n, nil, 0); err != nil {
+ return err
+ }
+
+ mib = []_C_int{CTL_KERN, KERN_OSRELEASE}
+ n = unsafe.Sizeof(uname.Release)
+ if err := sysctl(mib, &uname.Release[0], &n, nil, 0); err != nil {
+ return err
+ }
+
+ mib = []_C_int{CTL_KERN, KERN_VERSION}
+ n = unsafe.Sizeof(uname.Version)
+ if err := sysctl(mib, &uname.Version[0], &n, nil, 0); err != nil {
+ return err
+ }
+
+ // The version might have newlines or tabs in it, convert them to
+ // spaces.
+ for i, b := range uname.Version {
+ if b == '\n' || b == '\t' {
+ if i == len(uname.Version)-1 {
+ uname.Version[i] = 0
+ } else {
+ uname.Version[i] = ' '
+ }
+ }
+ }
+
+ mib = []_C_int{CTL_HW, HW_MACHINE}
+ n = unsafe.Sizeof(uname.Machine)
+ if err := sysctl(mib, &uname.Machine[0], &n, nil, 0); err != nil {
+ return err
+ }
+
+ return nil
}
-func IoctlSetWinsize(fd int, req uint, value *Winsize) error {
- return ioctl(fd, req, uintptr(unsafe.Pointer(value)))
+func Stat(path string, st *Stat_t) (err error) {
+ var oldStat stat_freebsd11_t
+ if supportsABI(_ino64First) {
+ return fstatat_freebsd12(AT_FDCWD, path, st, 0)
+ }
+ err = stat(path, &oldStat)
+ if err != nil {
+ return err
+ }
+
+ st.convertFrom(&oldStat)
+ return nil
}
-func IoctlSetTermios(fd int, req uint, value *Termios) error {
- return ioctl(fd, req, uintptr(unsafe.Pointer(value)))
+func Lstat(path string, st *Stat_t) (err error) {
+ var oldStat stat_freebsd11_t
+ if supportsABI(_ino64First) {
+ return fstatat_freebsd12(AT_FDCWD, path, st, AT_SYMLINK_NOFOLLOW)
+ }
+ err = lstat(path, &oldStat)
+ if err != nil {
+ return err
+ }
+
+ st.convertFrom(&oldStat)
+ return nil
}
-// IoctlGetInt performs an ioctl operation which gets an integer value
-// from fd, using the specified request number.
-func IoctlGetInt(fd int, req uint) (int, error) {
- var value int
- err := ioctl(fd, req, uintptr(unsafe.Pointer(&value)))
- return value, err
+func Fstat(fd int, st *Stat_t) (err error) {
+ var oldStat stat_freebsd11_t
+ if supportsABI(_ino64First) {
+ return fstat_freebsd12(fd, st)
+ }
+ err = fstat(fd, &oldStat)
+ if err != nil {
+ return err
+ }
+
+ st.convertFrom(&oldStat)
+ return nil
}
-func IoctlGetWinsize(fd int, req uint) (*Winsize, error) {
- var value Winsize
- err := ioctl(fd, req, uintptr(unsafe.Pointer(&value)))
- return &value, err
+func Fstatat(fd int, path string, st *Stat_t, flags int) (err error) {
+ var oldStat stat_freebsd11_t
+ if supportsABI(_ino64First) {
+ return fstatat_freebsd12(fd, path, st, flags)
+ }
+ err = fstatat(fd, path, &oldStat, flags)
+ if err != nil {
+ return err
+ }
+
+ st.convertFrom(&oldStat)
+ return nil
}
-func IoctlGetTermios(fd int, req uint) (*Termios, error) {
- var value Termios
- err := ioctl(fd, req, uintptr(unsafe.Pointer(&value)))
- return &value, err
+func Statfs(path string, st *Statfs_t) (err error) {
+ var oldStatfs statfs_freebsd11_t
+ if supportsABI(_ino64First) {
+ return statfs_freebsd12(path, st)
+ }
+ err = statfs(path, &oldStatfs)
+ if err != nil {
+ return err
+ }
+
+ st.convertFrom(&oldStatfs)
+ return nil
+}
+
+func Fstatfs(fd int, st *Statfs_t) (err error) {
+ var oldStatfs statfs_freebsd11_t
+ if supportsABI(_ino64First) {
+ return fstatfs_freebsd12(fd, st)
+ }
+ err = fstatfs(fd, &oldStatfs)
+ if err != nil {
+ return err
+ }
+
+ st.convertFrom(&oldStatfs)
+ return nil
+}
+
+func Getdents(fd int, buf []byte) (n int, err error) {
+ return Getdirentries(fd, buf, nil)
+}
+
+func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
+ if supportsABI(_ino64First) {
+ if basep == nil || unsafe.Sizeof(*basep) == 8 {
+ return getdirentries_freebsd12(fd, buf, (*uint64)(unsafe.Pointer(basep)))
+ }
+ // The freebsd12 syscall needs a 64-bit base. On 32-bit machines
+ // we can't just use the basep passed in. See #32498.
+ var base uint64 = uint64(*basep)
+ n, err = getdirentries_freebsd12(fd, buf, &base)
+ *basep = uintptr(base)
+ if base>>32 != 0 {
+ // We can't stuff the base back into a uintptr, so any
+ // future calls would be suspect. Generate an error.
+ // EIO is allowed by getdirentries.
+ err = EIO
+ }
+ return
+ }
+
+ // The old syscall entries are smaller than the new. Use 1/4 of the original
+ // buffer size rounded up to DIRBLKSIZ (see /usr/src/lib/libc/sys/getdirentries.c).
+ oldBufLen := roundup(len(buf)/4, _dirblksiz)
+ oldBuf := make([]byte, oldBufLen)
+ n, err = getdirentries(fd, oldBuf, basep)
+ if err == nil && n > 0 {
+ n = convertFromDirents11(buf, oldBuf[:n])
+ }
+ return
+}
+
+func Mknod(path string, mode uint32, dev uint64) (err error) {
+ var oldDev int
+ if supportsABI(_ino64First) {
+ return mknodat_freebsd12(AT_FDCWD, path, mode, dev)
+ }
+ oldDev = int(dev)
+ return mknod(path, mode, oldDev)
+}
+
+func Mknodat(fd int, path string, mode uint32, dev uint64) (err error) {
+ var oldDev int
+ if supportsABI(_ino64First) {
+ return mknodat_freebsd12(fd, path, mode, dev)
+ }
+ oldDev = int(dev)
+ return mknodat(fd, path, mode, oldDev)
+}
+
+// round x to the nearest multiple of y, larger or equal to x.
+//
+// from /usr/include/sys/param.h Macros for counting and rounding.
+// #define roundup(x, y) ((((x)+((y)-1))/(y))*(y))
+func roundup(x, y int) int {
+ return ((x + y - 1) / y) * y
+}
+
+func (s *Stat_t) convertFrom(old *stat_freebsd11_t) {
+ *s = Stat_t{
+ Dev: uint64(old.Dev),
+ Ino: uint64(old.Ino),
+ Nlink: uint64(old.Nlink),
+ Mode: old.Mode,
+ Uid: old.Uid,
+ Gid: old.Gid,
+ Rdev: uint64(old.Rdev),
+ Atim: old.Atim,
+ Mtim: old.Mtim,
+ Ctim: old.Ctim,
+ Btim: old.Btim,
+ Size: old.Size,
+ Blocks: old.Blocks,
+ Blksize: old.Blksize,
+ Flags: old.Flags,
+ Gen: uint64(old.Gen),
+ }
+}
+
+func (s *Statfs_t) convertFrom(old *statfs_freebsd11_t) {
+ *s = Statfs_t{
+ Version: _statfsVersion,
+ Type: old.Type,
+ Flags: old.Flags,
+ Bsize: old.Bsize,
+ Iosize: old.Iosize,
+ Blocks: old.Blocks,
+ Bfree: old.Bfree,
+ Bavail: old.Bavail,
+ Files: old.Files,
+ Ffree: old.Ffree,
+ Syncwrites: old.Syncwrites,
+ Asyncwrites: old.Asyncwrites,
+ Syncreads: old.Syncreads,
+ Asyncreads: old.Asyncreads,
+ // Spare
+ Namemax: old.Namemax,
+ Owner: old.Owner,
+ Fsid: old.Fsid,
+ // Charspare
+ // Fstypename
+ // Mntfromname
+ // Mntonname
+ }
+
+ sl := old.Fstypename[:]
+ n := clen(*(*[]byte)(unsafe.Pointer(&sl)))
+ copy(s.Fstypename[:], old.Fstypename[:n])
+
+ sl = old.Mntfromname[:]
+ n = clen(*(*[]byte)(unsafe.Pointer(&sl)))
+ copy(s.Mntfromname[:], old.Mntfromname[:n])
+
+ sl = old.Mntonname[:]
+ n = clen(*(*[]byte)(unsafe.Pointer(&sl)))
+ copy(s.Mntonname[:], old.Mntonname[:n])
+}
+
+func convertFromDirents11(buf []byte, old []byte) int {
+ const (
+ fixedSize = int(unsafe.Offsetof(Dirent{}.Name))
+ oldFixedSize = int(unsafe.Offsetof(dirent_freebsd11{}.Name))
+ )
+
+ dstPos := 0
+ srcPos := 0
+ for dstPos+fixedSize < len(buf) && srcPos+oldFixedSize < len(old) {
+ var dstDirent Dirent
+ var srcDirent dirent_freebsd11
+
+ // If multiple direntries are written, sometimes when we reach the final one,
+ // we may have cap of old less than size of dirent_freebsd11.
+ copy((*[unsafe.Sizeof(srcDirent)]byte)(unsafe.Pointer(&srcDirent))[:], old[srcPos:])
+
+ reclen := roundup(fixedSize+int(srcDirent.Namlen)+1, 8)
+ if dstPos+reclen > len(buf) {
+ break
+ }
+
+ dstDirent.Fileno = uint64(srcDirent.Fileno)
+ dstDirent.Off = 0
+ dstDirent.Reclen = uint16(reclen)
+ dstDirent.Type = srcDirent.Type
+ dstDirent.Pad0 = 0
+ dstDirent.Namlen = uint16(srcDirent.Namlen)
+ dstDirent.Pad1 = 0
+
+ copy(dstDirent.Name[:], srcDirent.Name[:srcDirent.Namlen])
+ copy(buf[dstPos:], (*[unsafe.Sizeof(dstDirent)]byte)(unsafe.Pointer(&dstDirent))[:])
+ padding := buf[dstPos+fixedSize+int(dstDirent.Namlen) : dstPos+reclen]
+ for i := range padding {
+ padding[i] = 0
+ }
+
+ dstPos += int(dstDirent.Reclen)
+ srcPos += int(srcDirent.Reclen)
+ }
+
+ return dstPos
+}
+
+func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
+ if raceenabled {
+ raceReleaseMerge(unsafe.Pointer(&ioSync))
+ }
+ return sendfile(outfd, infd, offset, count)
+}
+
+//sys ptrace(request int, pid int, addr uintptr, data int) (err error)
+
+func PtraceAttach(pid int) (err error) {
+ return ptrace(PTRACE_ATTACH, pid, 0, 0)
+}
+
+func PtraceCont(pid int, signal int) (err error) {
+ return ptrace(PTRACE_CONT, pid, 1, signal)
+}
+
+func PtraceDetach(pid int) (err error) {
+ return ptrace(PTRACE_DETACH, pid, 1, 0)
+}
+
+func PtraceGetFpRegs(pid int, fpregsout *FpReg) (err error) {
+ return ptrace(PTRACE_GETFPREGS, pid, uintptr(unsafe.Pointer(fpregsout)), 0)
+}
+
+func PtraceGetFsBase(pid int, fsbase *int64) (err error) {
+ return ptrace(PTRACE_GETFSBASE, pid, uintptr(unsafe.Pointer(fsbase)), 0)
+}
+
+func PtraceGetRegs(pid int, regsout *Reg) (err error) {
+ return ptrace(PTRACE_GETREGS, pid, uintptr(unsafe.Pointer(regsout)), 0)
+}
+
+func PtraceIO(req int, pid int, addr uintptr, out []byte, countin int) (count int, err error) {
+ ioDesc := PtraceIoDesc{Op: int32(req), Offs: (*byte)(unsafe.Pointer(addr)), Addr: (*byte)(unsafe.Pointer(&out[0])), Len: uint(countin)}
+ err = ptrace(PTRACE_IO, pid, uintptr(unsafe.Pointer(&ioDesc)), 0)
+ return int(ioDesc.Len), err
+}
+
+func PtraceLwpEvents(pid int, enable int) (err error) {
+ return ptrace(PTRACE_LWPEVENTS, pid, 0, enable)
+}
+
+func PtraceLwpInfo(pid int, info uintptr) (err error) {
+ return ptrace(PTRACE_LWPINFO, pid, info, int(unsafe.Sizeof(PtraceLwpInfoStruct{})))
+}
+
+func PtracePeekData(pid int, addr uintptr, out []byte) (count int, err error) {
+ return PtraceIO(PIOD_READ_D, pid, addr, out, SizeofLong)
+}
+
+func PtracePeekText(pid int, addr uintptr, out []byte) (count int, err error) {
+ return PtraceIO(PIOD_READ_I, pid, addr, out, SizeofLong)
+}
+
+func PtracePokeData(pid int, addr uintptr, data []byte) (count int, err error) {
+ return PtraceIO(PIOD_WRITE_D, pid, addr, data, SizeofLong)
+}
+
+func PtracePokeText(pid int, addr uintptr, data []byte) (count int, err error) {
+ return PtraceIO(PIOD_WRITE_I, pid, addr, data, SizeofLong)
+}
+
+func PtraceSetRegs(pid int, regs *Reg) (err error) {
+ return ptrace(PTRACE_SETREGS, pid, uintptr(unsafe.Pointer(regs)), 0)
+}
+
+func PtraceSingleStep(pid int) (err error) {
+ return ptrace(PTRACE_SINGLESTEP, pid, 1, 0)
}
/*
@@ -430,11 +606,16 @@ func IoctlGetTermios(fd int, req uint) (*Termios, error) {
//sys Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error)
//sys Flock(fd int, how int) (err error)
//sys Fpathconf(fd int, name int) (val int, err error)
-//sys Fstat(fd int, stat *Stat_t) (err error)
-//sys Fstatfs(fd int, stat *Statfs_t) (err error)
+//sys fstat(fd int, stat *stat_freebsd11_t) (err error)
+//sys fstat_freebsd12(fd int, stat *Stat_t) (err error)
+//sys fstatat(fd int, path string, stat *stat_freebsd11_t, flags int) (err error)
+//sys fstatat_freebsd12(fd int, path string, stat *Stat_t, flags int) (err error)
+//sys fstatfs(fd int, stat *statfs_freebsd11_t) (err error)
+//sys fstatfs_freebsd12(fd int, stat *Statfs_t) (err error)
//sys Fsync(fd int) (err error)
//sys Ftruncate(fd int, length int64) (err error)
-//sys Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error)
+//sys getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error)
+//sys getdirentries_freebsd12(fd int, buf []byte, basep *uint64) (n int, err error)
//sys Getdtablesize() (size int)
//sysnb Getegid() (egid int)
//sysnb Geteuid() (uid int)
@@ -456,11 +637,13 @@ func IoctlGetTermios(fd int, req uint) (*Termios, error) {
//sys Link(path string, link string) (err error)
//sys Linkat(pathfd int, path string, linkfd int, link string, flags int) (err error)
//sys Listen(s int, backlog int) (err error)
-//sys Lstat(path string, stat *Stat_t) (err error)
+//sys lstat(path string, stat *stat_freebsd11_t) (err error)
//sys Mkdir(path string, mode uint32) (err error)
//sys Mkdirat(dirfd int, path string, mode uint32) (err error)
//sys Mkfifo(path string, mode uint32) (err error)
-//sys Mknod(path string, mode uint32, dev int) (err error)
+//sys mknod(path string, mode uint32, dev int) (err error)
+//sys mknodat(fd int, path string, mode uint32, dev int) (err error)
+//sys mknodat_freebsd12(fd int, path string, mode uint32, dev uint64) (err error)
//sys Nanosleep(time *Timespec, leftover *Timespec) (err error)
//sys Open(path string, mode int, perm uint32) (fd int, err error)
//sys Openat(fdat int, path string, mode int, perm uint32) (fd int, err error)
@@ -475,7 +658,7 @@ func IoctlGetTermios(fd int, req uint) (*Termios, error) {
//sys Revoke(path string) (err error)
//sys Rmdir(path string) (err error)
//sys Seek(fd int, offset int64, whence int) (newoffset int64, err error) = SYS_LSEEK
-//sys Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error)
+//sys Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err error)
//sysnb Setegid(egid int) (err error)
//sysnb Seteuid(euid int) (err error)
//sysnb Setgid(gid int) (err error)
@@ -490,8 +673,9 @@ func IoctlGetTermios(fd int, req uint) (*Termios, error) {
//sysnb Setsid() (pid int, err error)
//sysnb Settimeofday(tp *Timeval) (err error)
//sysnb Setuid(uid int) (err error)
-//sys Stat(path string, stat *Stat_t) (err error)
-//sys Statfs(path string, stat *Statfs_t) (err error)
+//sys stat(path string, stat *stat_freebsd11_t) (err error)
+//sys statfs(path string, stat *statfs_freebsd11_t) (err error)
+//sys statfs_freebsd12(path string, stat *Statfs_t) (err error)
//sys Symlink(path string, link string) (err error)
//sys Symlinkat(oldpath string, newdirfd int, newpath string) (err error)
//sys Sync() (err error)
@@ -546,22 +730,14 @@ func IoctlGetTermios(fd int, req uint) (*Termios, error) {
// Kqueue_portset
// Getattrlist
// Setattrlist
+// Getdents
// Getdirentriesattr
// Searchfs
// Delete
// Copyfile
-// Poll
// Watchevent
// Waitevent
// Modwatch
-// Getxattr
-// Fgetxattr
-// Setxattr
-// Fsetxattr
-// Removexattr
-// Fremovexattr
-// Listxattr
-// Flistxattr
// Fsctl
// Initgroups
// Posix_spawn
diff --git a/vendor/golang.org/x/sys/unix/syscall_freebsd_386.go b/vendor/golang.org/x/sys/unix/syscall_freebsd_386.go
index 4cf5f45..dcc5645 100644
--- a/vendor/golang.org/x/sys/unix/syscall_freebsd_386.go
+++ b/vendor/golang.org/x/sys/unix/syscall_freebsd_386.go
@@ -11,19 +11,12 @@ import (
"unsafe"
)
-func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
-
-func NsecToTimespec(nsec int64) (ts Timespec) {
- ts.Sec = int32(nsec / 1e9)
- ts.Nsec = int32(nsec % 1e9)
- return
+func setTimespec(sec, nsec int64) Timespec {
+ return Timespec{Sec: int32(sec), Nsec: int32(nsec)}
}
-func NsecToTimeval(nsec int64) (tv Timeval) {
- nsec += 999 // round up to microsecond
- tv.Usec = int32(nsec % 1e9 / 1e3)
- tv.Sec = int32(nsec / 1e9)
- return
+func setTimeval(sec, usec int64) Timeval {
+ return Timeval{Sec: int32(sec), Usec: int32(usec)}
}
func SetKevent(k *Kevent_t, fd, mode, flags int) {
@@ -40,6 +33,10 @@ func (msghdr *Msghdr) SetControllen(length int) {
msghdr.Controllen = uint32(length)
}
+func (msghdr *Msghdr) SetIovlen(length int) {
+ msghdr.Iovlen = int32(length)
+}
+
func (cmsg *Cmsghdr) SetLen(length int) {
cmsg.Len = uint32(length)
}
diff --git a/vendor/golang.org/x/sys/unix/syscall_freebsd_amd64.go b/vendor/golang.org/x/sys/unix/syscall_freebsd_amd64.go
index b8036e7..321c3ba 100644
--- a/vendor/golang.org/x/sys/unix/syscall_freebsd_amd64.go
+++ b/vendor/golang.org/x/sys/unix/syscall_freebsd_amd64.go
@@ -11,19 +11,12 @@ import (
"unsafe"
)
-func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
-
-func NsecToTimespec(nsec int64) (ts Timespec) {
- ts.Sec = nsec / 1e9
- ts.Nsec = nsec % 1e9
- return
+func setTimespec(sec, nsec int64) Timespec {
+ return Timespec{Sec: sec, Nsec: nsec}
}
-func NsecToTimeval(nsec int64) (tv Timeval) {
- nsec += 999 // round up to microsecond
- tv.Usec = nsec % 1e9 / 1e3
- tv.Sec = int64(nsec / 1e9)
- return
+func setTimeval(sec, usec int64) Timeval {
+ return Timeval{Sec: sec, Usec: usec}
}
func SetKevent(k *Kevent_t, fd, mode, flags int) {
@@ -40,6 +33,10 @@ func (msghdr *Msghdr) SetControllen(length int) {
msghdr.Controllen = uint32(length)
}
+func (msghdr *Msghdr) SetIovlen(length int) {
+ msghdr.Iovlen = int32(length)
+}
+
func (cmsg *Cmsghdr) SetLen(length int) {
cmsg.Len = uint32(length)
}
diff --git a/vendor/golang.org/x/sys/unix/syscall_freebsd_arm.go b/vendor/golang.org/x/sys/unix/syscall_freebsd_arm.go
index 5a3bb6a..6977008 100644
--- a/vendor/golang.org/x/sys/unix/syscall_freebsd_arm.go
+++ b/vendor/golang.org/x/sys/unix/syscall_freebsd_arm.go
@@ -11,19 +11,12 @@ import (
"unsafe"
)
-func TimespecToNsec(ts Timespec) int64 { return ts.Sec*1e9 + int64(ts.Nsec) }
-
-func NsecToTimespec(nsec int64) (ts Timespec) {
- ts.Sec = nsec / 1e9
- ts.Nsec = int32(nsec % 1e9)
- return
+func setTimespec(sec, nsec int64) Timespec {
+ return Timespec{Sec: sec, Nsec: int32(nsec)}
}
-func NsecToTimeval(nsec int64) (tv Timeval) {
- nsec += 999 // round up to microsecond
- tv.Usec = int32(nsec % 1e9 / 1e3)
- tv.Sec = nsec / 1e9
- return
+func setTimeval(sec, usec int64) Timeval {
+ return Timeval{Sec: sec, Usec: int32(usec)}
}
func SetKevent(k *Kevent_t, fd, mode, flags int) {
@@ -40,6 +33,10 @@ func (msghdr *Msghdr) SetControllen(length int) {
msghdr.Controllen = uint32(length)
}
+func (msghdr *Msghdr) SetIovlen(length int) {
+ msghdr.Iovlen = int32(length)
+}
+
func (cmsg *Cmsghdr) SetLen(length int) {
cmsg.Len = uint32(length)
}
diff --git a/vendor/golang.org/x/sys/unix/syscall_freebsd_arm64.go b/vendor/golang.org/x/sys/unix/syscall_freebsd_arm64.go
new file mode 100644
index 0000000..dbbbfd6
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/syscall_freebsd_arm64.go
@@ -0,0 +1,56 @@
+// Copyright 2018 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 arm64,freebsd
+
+package unix
+
+import (
+ "syscall"
+ "unsafe"
+)
+
+func setTimespec(sec, nsec int64) Timespec {
+ return Timespec{Sec: sec, Nsec: nsec}
+}
+
+func setTimeval(sec, usec int64) Timeval {
+ return Timeval{Sec: sec, Usec: usec}
+}
+
+func SetKevent(k *Kevent_t, fd, mode, flags int) {
+ k.Ident = uint64(fd)
+ k.Filter = int16(mode)
+ k.Flags = uint16(flags)
+}
+
+func (iov *Iovec) SetLen(length int) {
+ iov.Len = uint64(length)
+}
+
+func (msghdr *Msghdr) SetControllen(length int) {
+ msghdr.Controllen = uint32(length)
+}
+
+func (msghdr *Msghdr) SetIovlen(length int) {
+ msghdr.Iovlen = int32(length)
+}
+
+func (cmsg *Cmsghdr) SetLen(length int) {
+ cmsg.Len = uint32(length)
+}
+
+func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
+ var writtenOut uint64 = 0
+ _, _, e1 := Syscall9(SYS_SENDFILE, uintptr(infd), uintptr(outfd), uintptr(*offset), uintptr(count), 0, uintptr(unsafe.Pointer(&writtenOut)), 0, 0, 0)
+
+ written = int(writtenOut)
+
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno)
diff --git a/vendor/golang.org/x/sys/unix/syscall_linux.go b/vendor/golang.org/x/sys/unix/syscall_linux.go
index 1b7d59d..b8837fc 100644
--- a/vendor/golang.org/x/sys/unix/syscall_linux.go
+++ b/vendor/golang.org/x/sys/unix/syscall_linux.go
@@ -12,6 +12,8 @@
package unix
import (
+ "encoding/binary"
+ "runtime"
"syscall"
"unsafe"
)
@@ -36,6 +38,20 @@ func Creat(path string, mode uint32) (fd int, err error) {
return Open(path, O_CREAT|O_WRONLY|O_TRUNC, mode)
}
+//sys FanotifyInit(flags uint, event_f_flags uint) (fd int, err error)
+//sys fanotifyMark(fd int, flags uint, mask uint64, dirFd int, pathname *byte) (err error)
+
+func FanotifyMark(fd int, flags uint, mask uint64, dirFd int, pathname string) (err error) {
+ if pathname == "" {
+ return fanotifyMark(fd, flags, mask, dirFd, nil)
+ }
+ p, err := BytePtrFromString(pathname)
+ if err != nil {
+ return err
+ }
+ return fanotifyMark(fd, flags, mask, dirFd, p)
+}
+
//sys fchmodat(dirfd int, path string, mode uint32) (err error)
func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) {
@@ -55,37 +71,41 @@ func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) {
// ioctl itself should not be exposed directly, but additional get/set
// functions for specific types are permissible.
-// IoctlSetInt performs an ioctl operation which sets an integer value
-// on fd, using the specified request number.
-func IoctlSetInt(fd int, req uint, value int) error {
- return ioctl(fd, req, uintptr(value))
+// IoctlRetInt performs an ioctl operation specified by req on a device
+// associated with opened file descriptor fd, and returns a non-negative
+// integer that is returned by the ioctl syscall.
+func IoctlRetInt(fd int, req uint) (int, error) {
+ ret, _, err := Syscall(SYS_IOCTL, uintptr(fd), uintptr(req), 0)
+ if err != 0 {
+ return 0, err
+ }
+ return int(ret), nil
}
-func IoctlSetWinsize(fd int, req uint, value *Winsize) error {
- return ioctl(fd, req, uintptr(unsafe.Pointer(value)))
+// IoctlSetPointerInt performs an ioctl operation which sets an
+// integer value on fd, using the specified request number. The ioctl
+// argument is called with a pointer to the integer value, rather than
+// passing the integer value directly.
+func IoctlSetPointerInt(fd int, req uint, value int) error {
+ v := int32(value)
+ return ioctl(fd, req, uintptr(unsafe.Pointer(&v)))
}
-func IoctlSetTermios(fd int, req uint, value *Termios) error {
- return ioctl(fd, req, uintptr(unsafe.Pointer(value)))
+func IoctlSetRTCTime(fd int, value *RTCTime) error {
+ err := ioctl(fd, RTC_SET_TIME, uintptr(unsafe.Pointer(value)))
+ runtime.KeepAlive(value)
+ return err
}
-// IoctlGetInt performs an ioctl operation which gets an integer value
-// from fd, using the specified request number.
-func IoctlGetInt(fd int, req uint) (int, error) {
- var value int
+func IoctlGetUint32(fd int, req uint) (uint32, error) {
+ var value uint32
err := ioctl(fd, req, uintptr(unsafe.Pointer(&value)))
return value, err
}
-func IoctlGetWinsize(fd int, req uint) (*Winsize, error) {
- var value Winsize
- err := ioctl(fd, req, uintptr(unsafe.Pointer(&value)))
- return &value, err
-}
-
-func IoctlGetTermios(fd int, req uint) (*Termios, error) {
- var value Termios
- err := ioctl(fd, req, uintptr(unsafe.Pointer(&value)))
+func IoctlGetRTCTime(fd int) (*RTCTime, error) {
+ var value RTCTime
+ err := ioctl(fd, RTC_RD_TIME, uintptr(unsafe.Pointer(&value)))
return &value, err
}
@@ -148,8 +168,6 @@ func Unlink(path string) error {
//sys Unlinkat(dirfd int, path string, flags int) (err error)
-//sys utimes(path string, times *[2]Timeval) (err error)
-
func Utimes(path string, tv []Timeval) error {
if tv == nil {
err := utimensat(AT_FDCWD, path, nil, 0)
@@ -207,20 +225,14 @@ func UtimesNanoAt(dirfd int, path string, ts []Timespec, flags int) error {
return utimensat(dirfd, path, (*[2]Timespec)(unsafe.Pointer(&ts[0])), flags)
}
-//sys futimesat(dirfd int, path *byte, times *[2]Timeval) (err error)
-
func Futimesat(dirfd int, path string, tv []Timeval) error {
- pathp, err := BytePtrFromString(path)
- if err != nil {
- return err
- }
if tv == nil {
- return futimesat(dirfd, pathp, nil)
+ return futimesat(dirfd, path, nil)
}
if len(tv) != 2 {
return EINVAL
}
- return futimesat(dirfd, pathp, (*[2]Timeval)(unsafe.Pointer(&tv[0])))
+ return futimesat(dirfd, path, (*[2]Timeval)(unsafe.Pointer(&tv[0])))
}
func Futimes(fd int, tv []Timeval) (err error) {
@@ -255,7 +267,7 @@ func Getgroups() (gids []int, err error) {
return nil, nil
}
- // Sanity check group count. Max is 1<<16 on Linux.
+ // Sanity check group count. Max is 1<<16 on Linux.
if n < 0 || n > 1<<20 {
return nil, EINVAL
}
@@ -290,8 +302,8 @@ type WaitStatus uint32
// 0x7F (stopped), or a signal number that caused an exit.
// The 0x80 bit is whether there was a core dump.
// An extra number (exit code, signal causing a stop)
-// is in the high bits. At least that's the idea.
-// There are various irregularities. For example, the
+// is in the high bits. At least that's the idea.
+// There are various irregularities. For example, the
// "continued" status is 0xFFFF, distinguishing itself
// from stopped via the core dump bit.
@@ -413,6 +425,7 @@ func (sa *SockaddrUnix) sockaddr() (unsafe.Pointer, _Socklen, error) {
return unsafe.Pointer(&sa.raw), sl, nil
}
+// SockaddrLinklayer implements the Sockaddr interface for AF_PACKET type sockets.
type SockaddrLinklayer struct {
Protocol uint16
Ifindex int
@@ -439,6 +452,7 @@ func (sa *SockaddrLinklayer) sockaddr() (unsafe.Pointer, _Socklen, error) {
return unsafe.Pointer(&sa.raw), SizeofSockaddrLinklayer, nil
}
+// SockaddrNetlink implements the Sockaddr interface for AF_NETLINK type sockets.
type SockaddrNetlink struct {
Family uint16
Pad uint16
@@ -455,6 +469,8 @@ func (sa *SockaddrNetlink) sockaddr() (unsafe.Pointer, _Socklen, error) {
return unsafe.Pointer(&sa.raw), SizeofSockaddrNetlink, nil
}
+// SockaddrHCI implements the Sockaddr interface for AF_BLUETOOTH type sockets
+// using the HCI protocol.
type SockaddrHCI struct {
Dev uint16
Channel uint16
@@ -468,6 +484,72 @@ func (sa *SockaddrHCI) sockaddr() (unsafe.Pointer, _Socklen, error) {
return unsafe.Pointer(&sa.raw), SizeofSockaddrHCI, nil
}
+// SockaddrL2 implements the Sockaddr interface for AF_BLUETOOTH type sockets
+// using the L2CAP protocol.
+type SockaddrL2 struct {
+ PSM uint16
+ CID uint16
+ Addr [6]uint8
+ AddrType uint8
+ raw RawSockaddrL2
+}
+
+func (sa *SockaddrL2) sockaddr() (unsafe.Pointer, _Socklen, error) {
+ sa.raw.Family = AF_BLUETOOTH
+ psm := (*[2]byte)(unsafe.Pointer(&sa.raw.Psm))
+ psm[0] = byte(sa.PSM)
+ psm[1] = byte(sa.PSM >> 8)
+ for i := 0; i < len(sa.Addr); i++ {
+ sa.raw.Bdaddr[i] = sa.Addr[len(sa.Addr)-1-i]
+ }
+ cid := (*[2]byte)(unsafe.Pointer(&sa.raw.Cid))
+ cid[0] = byte(sa.CID)
+ cid[1] = byte(sa.CID >> 8)
+ sa.raw.Bdaddr_type = sa.AddrType
+ return unsafe.Pointer(&sa.raw), SizeofSockaddrL2, nil
+}
+
+// SockaddrRFCOMM implements the Sockaddr interface for AF_BLUETOOTH type sockets
+// using the RFCOMM protocol.
+//
+// Server example:
+//
+// fd, _ := Socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM)
+// _ = unix.Bind(fd, &unix.SockaddrRFCOMM{
+// Channel: 1,
+// Addr: [6]uint8{0, 0, 0, 0, 0, 0}, // BDADDR_ANY or 00:00:00:00:00:00
+// })
+// _ = Listen(fd, 1)
+// nfd, sa, _ := Accept(fd)
+// fmt.Printf("conn addr=%v fd=%d", sa.(*unix.SockaddrRFCOMM).Addr, nfd)
+// Read(nfd, buf)
+//
+// Client example:
+//
+// fd, _ := Socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM)
+// _ = Connect(fd, &SockaddrRFCOMM{
+// Channel: 1,
+// Addr: [6]byte{0x11, 0x22, 0x33, 0xaa, 0xbb, 0xcc}, // CC:BB:AA:33:22:11
+// })
+// Write(fd, []byte(`hello`))
+type SockaddrRFCOMM struct {
+ // Addr represents a bluetooth address, byte ordering is little-endian.
+ Addr [6]uint8
+
+ // Channel is a designated bluetooth channel, only 1-30 are available for use.
+ // Since Linux 2.6.7 and further zero value is the first available channel.
+ Channel uint8
+
+ raw RawSockaddrRFCOMM
+}
+
+func (sa *SockaddrRFCOMM) sockaddr() (unsafe.Pointer, _Socklen, error) {
+ sa.raw.Family = AF_BLUETOOTH
+ sa.raw.Channel = sa.Channel
+ sa.raw.Bdaddr = sa.Addr
+ return unsafe.Pointer(&sa.raw), SizeofSockaddrRFCOMM, nil
+}
+
// SockaddrCAN implements the Sockaddr interface for AF_CAN type sockets.
// The RxID and TxID fields are used for transport protocol addressing in
// (CAN_TP16, CAN_TP20, CAN_MCNET, and CAN_ISOTP), they can be left with
@@ -630,7 +712,134 @@ func (sa *SockaddrVM) sockaddr() (unsafe.Pointer, _Socklen, error) {
return unsafe.Pointer(&sa.raw), SizeofSockaddrVM, nil
}
-func anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, error) {
+type SockaddrXDP struct {
+ Flags uint16
+ Ifindex uint32
+ QueueID uint32
+ SharedUmemFD uint32
+ raw RawSockaddrXDP
+}
+
+func (sa *SockaddrXDP) sockaddr() (unsafe.Pointer, _Socklen, error) {
+ sa.raw.Family = AF_XDP
+ sa.raw.Flags = sa.Flags
+ sa.raw.Ifindex = sa.Ifindex
+ sa.raw.Queue_id = sa.QueueID
+ sa.raw.Shared_umem_fd = sa.SharedUmemFD
+
+ return unsafe.Pointer(&sa.raw), SizeofSockaddrXDP, nil
+}
+
+// This constant mirrors the #define of PX_PROTO_OE in
+// linux/if_pppox.h. We're defining this by hand here instead of
+// autogenerating through mkerrors.sh because including
+// linux/if_pppox.h causes some declaration conflicts with other
+// includes (linux/if_pppox.h includes linux/in.h, which conflicts
+// with netinet/in.h). Given that we only need a single zero constant
+// out of that file, it's cleaner to just define it by hand here.
+const px_proto_oe = 0
+
+type SockaddrPPPoE struct {
+ SID uint16
+ Remote []byte
+ Dev string
+ raw RawSockaddrPPPoX
+}
+
+func (sa *SockaddrPPPoE) sockaddr() (unsafe.Pointer, _Socklen, error) {
+ if len(sa.Remote) != 6 {
+ return nil, 0, EINVAL
+ }
+ if len(sa.Dev) > IFNAMSIZ-1 {
+ return nil, 0, EINVAL
+ }
+
+ *(*uint16)(unsafe.Pointer(&sa.raw[0])) = AF_PPPOX
+ // This next field is in host-endian byte order. We can't use the
+ // same unsafe pointer cast as above, because this value is not
+ // 32-bit aligned and some architectures don't allow unaligned
+ // access.
+ //
+ // However, the value of px_proto_oe is 0, so we can use
+ // encoding/binary helpers to write the bytes without worrying
+ // about the ordering.
+ binary.BigEndian.PutUint32(sa.raw[2:6], px_proto_oe)
+ // This field is deliberately big-endian, unlike the previous
+ // one. The kernel expects SID to be in network byte order.
+ binary.BigEndian.PutUint16(sa.raw[6:8], sa.SID)
+ copy(sa.raw[8:14], sa.Remote)
+ for i := 14; i < 14+IFNAMSIZ; i++ {
+ sa.raw[i] = 0
+ }
+ copy(sa.raw[14:], sa.Dev)
+ return unsafe.Pointer(&sa.raw), SizeofSockaddrPPPoX, nil
+}
+
+// SockaddrTIPC implements the Sockaddr interface for AF_TIPC type sockets.
+// For more information on TIPC, see: http://tipc.sourceforge.net/.
+type SockaddrTIPC struct {
+ // Scope is the publication scopes when binding service/service range.
+ // Should be set to TIPC_CLUSTER_SCOPE or TIPC_NODE_SCOPE.
+ Scope int
+
+ // Addr is the type of address used to manipulate a socket. Addr must be
+ // one of:
+ // - *TIPCSocketAddr: "id" variant in the C addr union
+ // - *TIPCServiceRange: "nameseq" variant in the C addr union
+ // - *TIPCServiceName: "name" variant in the C addr union
+ //
+ // If nil, EINVAL will be returned when the structure is used.
+ Addr TIPCAddr
+
+ raw RawSockaddrTIPC
+}
+
+// TIPCAddr is implemented by types that can be used as an address for
+// SockaddrTIPC. It is only implemented by *TIPCSocketAddr, *TIPCServiceRange,
+// and *TIPCServiceName.
+type TIPCAddr interface {
+ tipcAddrtype() uint8
+ tipcAddr() [12]byte
+}
+
+func (sa *TIPCSocketAddr) tipcAddr() [12]byte {
+ var out [12]byte
+ copy(out[:], (*(*[unsafe.Sizeof(TIPCSocketAddr{})]byte)(unsafe.Pointer(sa)))[:])
+ return out
+}
+
+func (sa *TIPCSocketAddr) tipcAddrtype() uint8 { return TIPC_SOCKET_ADDR }
+
+func (sa *TIPCServiceRange) tipcAddr() [12]byte {
+ var out [12]byte
+ copy(out[:], (*(*[unsafe.Sizeof(TIPCServiceRange{})]byte)(unsafe.Pointer(sa)))[:])
+ return out
+}
+
+func (sa *TIPCServiceRange) tipcAddrtype() uint8 { return TIPC_SERVICE_RANGE }
+
+func (sa *TIPCServiceName) tipcAddr() [12]byte {
+ var out [12]byte
+ copy(out[:], (*(*[unsafe.Sizeof(TIPCServiceName{})]byte)(unsafe.Pointer(sa)))[:])
+ return out
+}
+
+func (sa *TIPCServiceName) tipcAddrtype() uint8 { return TIPC_SERVICE_ADDR }
+
+func (sa *SockaddrTIPC) sockaddr() (unsafe.Pointer, _Socklen, error) {
+ if sa.Addr == nil {
+ return nil, 0, EINVAL
+ }
+
+ sa.raw.Family = AF_TIPC
+ sa.raw.Scope = int8(sa.Scope)
+ sa.raw.Addrtype = sa.Addr.tipcAddrtype()
+ sa.raw.Addr = sa.Addr.tipcAddr()
+
+ return unsafe.Pointer(&sa.raw), SizeofSockaddrTIPC, nil
+}
+
+func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) {
switch rsa.Addr.Family {
case AF_NETLINK:
pp := (*RawSockaddrNetlink)(unsafe.Pointer(rsa))
@@ -675,7 +884,7 @@ func anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, error) {
for n < len(pp.Path) && pp.Path[n] != 0 {
n++
}
- bytes := (*[10000]byte)(unsafe.Pointer(&pp.Path[0]))[0:n]
+ bytes := (*[len(pp.Path)]byte)(unsafe.Pointer(&pp.Path[0]))[0:n]
sa.Name = string(bytes)
return sa, nil
@@ -706,6 +915,76 @@ func anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, error) {
CID: pp.Cid,
Port: pp.Port,
}
+ return sa, nil
+ case AF_BLUETOOTH:
+ proto, err := GetsockoptInt(fd, SOL_SOCKET, SO_PROTOCOL)
+ if err != nil {
+ return nil, err
+ }
+ // only BTPROTO_L2CAP and BTPROTO_RFCOMM can accept connections
+ switch proto {
+ case BTPROTO_L2CAP:
+ pp := (*RawSockaddrL2)(unsafe.Pointer(rsa))
+ sa := &SockaddrL2{
+ PSM: pp.Psm,
+ CID: pp.Cid,
+ Addr: pp.Bdaddr,
+ AddrType: pp.Bdaddr_type,
+ }
+ return sa, nil
+ case BTPROTO_RFCOMM:
+ pp := (*RawSockaddrRFCOMM)(unsafe.Pointer(rsa))
+ sa := &SockaddrRFCOMM{
+ Channel: pp.Channel,
+ Addr: pp.Bdaddr,
+ }
+ return sa, nil
+ }
+ case AF_XDP:
+ pp := (*RawSockaddrXDP)(unsafe.Pointer(rsa))
+ sa := &SockaddrXDP{
+ Flags: pp.Flags,
+ Ifindex: pp.Ifindex,
+ QueueID: pp.Queue_id,
+ SharedUmemFD: pp.Shared_umem_fd,
+ }
+ return sa, nil
+ case AF_PPPOX:
+ pp := (*RawSockaddrPPPoX)(unsafe.Pointer(rsa))
+ if binary.BigEndian.Uint32(pp[2:6]) != px_proto_oe {
+ return nil, EINVAL
+ }
+ sa := &SockaddrPPPoE{
+ SID: binary.BigEndian.Uint16(pp[6:8]),
+ Remote: pp[8:14],
+ }
+ for i := 14; i < 14+IFNAMSIZ; i++ {
+ if pp[i] == 0 {
+ sa.Dev = string(pp[14:i])
+ break
+ }
+ }
+ return sa, nil
+ case AF_TIPC:
+ pp := (*RawSockaddrTIPC)(unsafe.Pointer(rsa))
+
+ sa := &SockaddrTIPC{
+ Scope: int(pp.Scope),
+ }
+
+ // Determine which union variant is present in pp.Addr by checking
+ // pp.Addrtype.
+ switch pp.Addrtype {
+ case TIPC_SERVICE_RANGE:
+ sa.Addr = (*TIPCServiceRange)(unsafe.Pointer(&pp.Addr))
+ case TIPC_SERVICE_ADDR:
+ sa.Addr = (*TIPCServiceName)(unsafe.Pointer(&pp.Addr))
+ case TIPC_SOCKET_ADDR:
+ sa.Addr = (*TIPCSocketAddr)(unsafe.Pointer(&pp.Addr))
+ default:
+ return nil, EINVAL
+ }
+
return sa, nil
}
return nil, EAFNOSUPPORT
@@ -718,7 +997,7 @@ func Accept(fd int) (nfd int, sa Sockaddr, err error) {
if err != nil {
return
}
- sa, err = anyToSockaddr(&rsa)
+ sa, err = anyToSockaddr(fd, &rsa)
if err != nil {
Close(nfd)
nfd = 0
@@ -736,7 +1015,7 @@ func Accept4(fd int, flags int) (nfd int, sa Sockaddr, err error) {
if len > SizeofSockaddrAny {
panic("RawSockaddrAny too small")
}
- sa, err = anyToSockaddr(&rsa)
+ sa, err = anyToSockaddr(fd, &rsa)
if err != nil {
Close(nfd)
nfd = 0
@@ -750,20 +1029,7 @@ func Getsockname(fd int) (sa Sockaddr, err error) {
if err = getsockname(fd, &rsa, &len); err != nil {
return
}
- return anyToSockaddr(&rsa)
-}
-
-func GetsockoptInet4Addr(fd, level, opt int) (value [4]byte, err error) {
- vallen := _Socklen(4)
- err = getsockopt(fd, level, opt, unsafe.Pointer(&value[0]), &vallen)
- return value, err
-}
-
-func GetsockoptIPMreq(fd, level, opt int) (*IPMreq, error) {
- var value IPMreq
- vallen := _Socklen(SizeofIPMreq)
- err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen)
- return &value, err
+ return anyToSockaddr(fd, &rsa)
}
func GetsockoptIPMreqn(fd, level, opt int) (*IPMreqn, error) {
@@ -773,27 +1039,6 @@ func GetsockoptIPMreqn(fd, level, opt int) (*IPMreqn, error) {
return &value, err
}
-func GetsockoptIPv6Mreq(fd, level, opt int) (*IPv6Mreq, error) {
- var value IPv6Mreq
- vallen := _Socklen(SizeofIPv6Mreq)
- err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen)
- return &value, err
-}
-
-func GetsockoptIPv6MTUInfo(fd, level, opt int) (*IPv6MTUInfo, error) {
- var value IPv6MTUInfo
- vallen := _Socklen(SizeofIPv6MTUInfo)
- err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen)
- return &value, err
-}
-
-func GetsockoptICMPv6Filter(fd, level, opt int) (*ICMPv6Filter, error) {
- var value ICMPv6Filter
- vallen := _Socklen(SizeofICMPv6Filter)
- err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen)
- return &value, err
-}
-
func GetsockoptUcred(fd, level, opt int) (*Ucred, error) {
var value Ucred
vallen := _Socklen(SizeofUcred)
@@ -808,10 +1053,68 @@ func GetsockoptTCPInfo(fd, level, opt int) (*TCPInfo, error) {
return &value, err
}
+// GetsockoptString returns the string value of the socket option opt for the
+// socket associated with fd at the given socket level.
+func GetsockoptString(fd, level, opt int) (string, error) {
+ buf := make([]byte, 256)
+ vallen := _Socklen(len(buf))
+ err := getsockopt(fd, level, opt, unsafe.Pointer(&buf[0]), &vallen)
+ if err != nil {
+ if err == ERANGE {
+ buf = make([]byte, vallen)
+ err = getsockopt(fd, level, opt, unsafe.Pointer(&buf[0]), &vallen)
+ }
+ if err != nil {
+ return "", err
+ }
+ }
+ return string(buf[:vallen-1]), nil
+}
+
+func GetsockoptTpacketStats(fd, level, opt int) (*TpacketStats, error) {
+ var value TpacketStats
+ vallen := _Socklen(SizeofTpacketStats)
+ err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen)
+ return &value, err
+}
+
+func GetsockoptTpacketStatsV3(fd, level, opt int) (*TpacketStatsV3, error) {
+ var value TpacketStatsV3
+ vallen := _Socklen(SizeofTpacketStatsV3)
+ err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen)
+ return &value, err
+}
+
func SetsockoptIPMreqn(fd, level, opt int, mreq *IPMreqn) (err error) {
return setsockopt(fd, level, opt, unsafe.Pointer(mreq), unsafe.Sizeof(*mreq))
}
+func SetsockoptPacketMreq(fd, level, opt int, mreq *PacketMreq) error {
+ return setsockopt(fd, level, opt, unsafe.Pointer(mreq), unsafe.Sizeof(*mreq))
+}
+
+// SetsockoptSockFprog attaches a classic BPF or an extended BPF program to a
+// socket to filter incoming packets. See 'man 7 socket' for usage information.
+func SetsockoptSockFprog(fd, level, opt int, fprog *SockFprog) error {
+ return setsockopt(fd, level, opt, unsafe.Pointer(fprog), unsafe.Sizeof(*fprog))
+}
+
+func SetsockoptCanRawFilter(fd, level, opt int, filter []CanFilter) error {
+ var p unsafe.Pointer
+ if len(filter) > 0 {
+ p = unsafe.Pointer(&filter[0])
+ }
+ return setsockopt(fd, level, opt, p, uintptr(len(filter)*SizeofCanFilter))
+}
+
+func SetsockoptTpacketReq(fd, level, opt int, tp *TpacketReq) error {
+ return setsockopt(fd, level, opt, unsafe.Pointer(tp), unsafe.Sizeof(*tp))
+}
+
+func SetsockoptTpacketReq3(fd, level, opt int, tp *TpacketReq3) error {
+ return setsockopt(fd, level, opt, unsafe.Pointer(tp), unsafe.Sizeof(*tp))
+}
+
// Keyctl Commands (http://man7.org/linux/man-pages/man2/keyctl.2.html)
// KeyctlInt calls keyctl commands in which each argument is an int.
@@ -919,6 +1222,34 @@ func KeyctlDHCompute(params *KeyctlDHParams, buffer []byte) (size int, err error
return keyctlDH(KEYCTL_DH_COMPUTE, params, buffer)
}
+// KeyctlRestrictKeyring implements the KEYCTL_RESTRICT_KEYRING command. This
+// command limits the set of keys that can be linked to the keyring, regardless
+// of keyring permissions. The command requires the "setattr" permission.
+//
+// When called with an empty keyType the command locks the keyring, preventing
+// any further keys from being linked to the keyring.
+//
+// The "asymmetric" keyType defines restrictions requiring key payloads to be
+// DER encoded X.509 certificates signed by keys in another keyring. Restrictions
+// for "asymmetric" include "builtin_trusted", "builtin_and_secondary_trusted",
+// "key_or_keyring:", and "key_or_keyring::chain".
+//
+// As of Linux 4.12, only the "asymmetric" keyType defines type-specific
+// restrictions.
+//
+// See the full documentation at:
+// http://man7.org/linux/man-pages/man3/keyctl_restrict_keyring.3.html
+// http://man7.org/linux/man-pages/man2/keyctl.2.html
+func KeyctlRestrictKeyring(ringid int, keyType string, restriction string) error {
+ if keyType == "" {
+ return keyctlRestrictKeyring(KEYCTL_RESTRICT_KEYRING, ringid)
+ }
+ return keyctlRestrictKeyringByType(KEYCTL_RESTRICT_KEYRING, ringid, keyType, restriction)
+}
+
+//sys keyctlRestrictKeyringByType(cmd int, arg2 int, keyType string, restriction string) (err error) = SYS_KEYCTL
+//sys keyctlRestrictKeyring(cmd int, arg2 int) (err error) = SYS_KEYCTL
+
func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from Sockaddr, err error) {
var msg Msghdr
var rsa RawSockaddrAny
@@ -926,22 +1257,24 @@ func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from
msg.Namelen = uint32(SizeofSockaddrAny)
var iov Iovec
if len(p) > 0 {
- iov.Base = (*byte)(unsafe.Pointer(&p[0]))
+ iov.Base = &p[0]
iov.SetLen(len(p))
}
var dummy byte
if len(oob) > 0 {
- var sockType int
- sockType, err = GetsockoptInt(fd, SOL_SOCKET, SO_TYPE)
- if err != nil {
- return
+ if len(p) == 0 {
+ var sockType int
+ sockType, err = GetsockoptInt(fd, SOL_SOCKET, SO_TYPE)
+ if err != nil {
+ return
+ }
+ // receive at least one normal byte
+ if sockType != SOCK_DGRAM {
+ iov.Base = &dummy
+ iov.SetLen(1)
+ }
}
- // receive at least one normal byte
- if sockType != SOCK_DGRAM && len(p) == 0 {
- iov.Base = &dummy
- iov.SetLen(1)
- }
- msg.Control = (*byte)(unsafe.Pointer(&oob[0]))
+ msg.Control = &oob[0]
msg.SetControllen(len(oob))
}
msg.Iov = &iov
@@ -953,7 +1286,7 @@ func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from
recvflags = int(msg.Flags)
// source address is only specified if the socket is unconnected
if rsa.Addr.Family != AF_UNSPEC {
- from, err = anyToSockaddr(&rsa)
+ from, err = anyToSockaddr(fd, &rsa)
}
return
}
@@ -974,26 +1307,28 @@ func SendmsgN(fd int, p, oob []byte, to Sockaddr, flags int) (n int, err error)
}
}
var msg Msghdr
- msg.Name = (*byte)(unsafe.Pointer(ptr))
+ msg.Name = (*byte)(ptr)
msg.Namelen = uint32(salen)
var iov Iovec
if len(p) > 0 {
- iov.Base = (*byte)(unsafe.Pointer(&p[0]))
+ iov.Base = &p[0]
iov.SetLen(len(p))
}
var dummy byte
if len(oob) > 0 {
- var sockType int
- sockType, err = GetsockoptInt(fd, SOL_SOCKET, SO_TYPE)
- if err != nil {
- return 0, err
+ if len(p) == 0 {
+ var sockType int
+ sockType, err = GetsockoptInt(fd, SOL_SOCKET, SO_TYPE)
+ if err != nil {
+ return 0, err
+ }
+ // send at least one normal byte
+ if sockType != SOCK_DGRAM {
+ iov.Base = &dummy
+ iov.SetLen(1)
+ }
}
- // send at least one normal byte
- if sockType != SOCK_DGRAM && len(p) == 0 {
- iov.Base = &dummy
- iov.SetLen(1)
- }
- msg.Control = (*byte)(unsafe.Pointer(&oob[0]))
+ msg.Control = &oob[0]
msg.SetControllen(len(oob))
}
msg.Iov = &iov
@@ -1021,20 +1356,20 @@ func ptracePeek(req int, pid int, addr uintptr, out []byte) (count int, err erro
// The ptrace syscall differs from glibc's ptrace.
// Peeks returns the word in *data, not as the return value.
- var buf [sizeofPtr]byte
+ var buf [SizeofPtr]byte
- // Leading edge. PEEKTEXT/PEEKDATA don't require aligned
+ // Leading edge. PEEKTEXT/PEEKDATA don't require aligned
// access (PEEKUSER warns that it might), but if we don't
// align our reads, we might straddle an unmapped page
// boundary and not get the bytes leading up to the page
// boundary.
n := 0
- if addr%sizeofPtr != 0 {
- err = ptrace(req, pid, addr-addr%sizeofPtr, uintptr(unsafe.Pointer(&buf[0])))
+ if addr%SizeofPtr != 0 {
+ err = ptrace(req, pid, addr-addr%SizeofPtr, uintptr(unsafe.Pointer(&buf[0])))
if err != nil {
return 0, err
}
- n += copy(out, buf[addr%sizeofPtr:])
+ n += copy(out, buf[addr%SizeofPtr:])
out = out[n:]
}
@@ -1072,15 +1407,15 @@ func ptracePoke(pokeReq int, peekReq int, pid int, addr uintptr, data []byte) (c
// Leading edge.
n := 0
- if addr%sizeofPtr != 0 {
- var buf [sizeofPtr]byte
- err = ptrace(peekReq, pid, addr-addr%sizeofPtr, uintptr(unsafe.Pointer(&buf[0])))
+ if addr%SizeofPtr != 0 {
+ var buf [SizeofPtr]byte
+ err = ptrace(peekReq, pid, addr-addr%SizeofPtr, uintptr(unsafe.Pointer(&buf[0])))
if err != nil {
return 0, err
}
- n += copy(buf[addr%sizeofPtr:], data)
+ n += copy(buf[addr%SizeofPtr:], data)
word := *((*uintptr)(unsafe.Pointer(&buf[0])))
- err = ptrace(pokeReq, pid, addr-addr%sizeofPtr, word)
+ err = ptrace(pokeReq, pid, addr-addr%SizeofPtr, word)
if err != nil {
return 0, err
}
@@ -1088,19 +1423,19 @@ func ptracePoke(pokeReq int, peekReq int, pid int, addr uintptr, data []byte) (c
}
// Interior.
- for len(data) > sizeofPtr {
+ for len(data) > SizeofPtr {
word := *((*uintptr)(unsafe.Pointer(&data[0])))
err = ptrace(pokeReq, pid, addr+uintptr(n), word)
if err != nil {
return n, err
}
- n += sizeofPtr
- data = data[sizeofPtr:]
+ n += SizeofPtr
+ data = data[SizeofPtr:]
}
// Trailing edge.
if len(data) > 0 {
- var buf [sizeofPtr]byte
+ var buf [SizeofPtr]byte
err = ptrace(peekReq, pid, addr+uintptr(n), uintptr(unsafe.Pointer(&buf[0])))
if err != nil {
return n, err
@@ -1125,6 +1460,10 @@ func PtracePokeData(pid int, addr uintptr, data []byte) (count int, err error) {
return ptracePoke(PTRACE_POKEDATA, PTRACE_PEEKDATA, pid, addr, data)
}
+func PtracePokeUser(pid int, addr uintptr, data []byte) (count int, err error) {
+ return ptracePoke(PTRACE_POKEUSR, PTRACE_PEEKUSR, pid, addr, data)
+}
+
func PtraceGetRegs(pid int, regsout *PtraceRegs) (err error) {
return ptrace(PTRACE_GETREGS, pid, 0, uintptr(unsafe.Pointer(regsout)))
}
@@ -1154,8 +1493,12 @@ func PtraceSyscall(pid int, signal int) (err error) {
func PtraceSingleStep(pid int) (err error) { return ptrace(PTRACE_SINGLESTEP, pid, 0, 0) }
+func PtraceInterrupt(pid int) (err error) { return ptrace(PTRACE_INTERRUPT, pid, 0, 0) }
+
func PtraceAttach(pid int) (err error) { return ptrace(PTRACE_ATTACH, pid, 0, 0) }
+func PtraceSeize(pid int) (err error) { return ptrace(PTRACE_SEIZE, pid, 0, 0) }
+
func PtraceDetach(pid int) (err error) { return ptrace(PTRACE_DETACH, pid, 0, 0) }
//sys reboot(magic1 uint, magic2 uint, cmd int, arg string) (err error)
@@ -1164,10 +1507,6 @@ func Reboot(cmd int) (err error) {
return reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, cmd, "")
}
-func ReadDirent(fd int, buf []byte) (n int, err error) {
- return Getdents(fd, buf)
-}
-
func direntIno(buf []byte) (uint64, bool) {
return readInt(buf, unsafe.Offsetof(Dirent{}.Ino), unsafe.Sizeof(Dirent{}.Ino))
}
@@ -1199,6 +1538,13 @@ func Mount(source string, target string, fstype string, flags uintptr, data stri
return mount(source, target, fstype, flags, datap)
}
+func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
+ if raceenabled {
+ raceReleaseMerge(unsafe.Pointer(&ioSync))
+ }
+ return sendfile(outfd, infd, offset, count)
+}
+
// Sendto
// Recvfrom
// Socketpair
@@ -1209,26 +1555,33 @@ func Mount(source string, target string, fstype string, flags uintptr, data stri
//sys Acct(path string) (err error)
//sys AddKey(keyType string, description string, payload []byte, ringid int) (id int, err error)
//sys Adjtimex(buf *Timex) (state int, err error)
+//sys Capget(hdr *CapUserHeader, data *CapUserData) (err error)
+//sys Capset(hdr *CapUserHeader, data *CapUserData) (err error)
//sys Chdir(path string) (err error)
//sys Chroot(path string) (err error)
+//sys ClockGetres(clockid int32, res *Timespec) (err error)
//sys ClockGettime(clockid int32, time *Timespec) (err error)
+//sys ClockNanosleep(clockid int32, flags int, request *Timespec, remain *Timespec) (err error)
//sys Close(fd int) (err error)
//sys CopyFileRange(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int, err error)
+//sys DeleteModule(name string, flags int) (err error)
//sys Dup(oldfd int) (fd int, err error)
//sys Dup3(oldfd int, newfd int, flags int) (err error)
-//sysnb EpollCreate(size int) (fd int, err error)
//sysnb EpollCreate1(flag int) (fd int, err error)
//sysnb EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error)
//sys Eventfd(initval uint, flags int) (fd int, err error) = SYS_EVENTFD2
//sys Exit(code int) = SYS_EXIT_GROUP
-//sys Faccessat(dirfd int, path string, mode uint32, flags int) (err error)
//sys Fallocate(fd int, mode uint32, off int64, len int64) (err error)
//sys Fchdir(fd int) (err error)
//sys Fchmod(fd int, mode uint32) (err error)
//sys Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error)
-//sys fcntl(fd int, cmd int, arg int) (val int, err error)
//sys Fdatasync(fd int) (err error)
+//sys Fgetxattr(fd int, attr string, dest []byte) (sz int, err error)
+//sys FinitModule(fd int, params string, flags int) (err error)
+//sys Flistxattr(fd int, dest []byte) (sz int, err error)
//sys Flock(fd int, how int) (err error)
+//sys Fremovexattr(fd int, attr string) (err error)
+//sys Fsetxattr(fd int, attr string, dest []byte, flags int) (err error)
//sys Fsync(fd int) (err error)
//sys Getdents(fd int, buf []byte) (n int, err error) = SYS_GETDENTS64
//sysnb Getpgid(pid int) (pgid int, err error)
@@ -1246,6 +1599,7 @@ func Getpgrp() (pid int) {
//sysnb Getsid(pid int) (sid int, err error)
//sysnb Gettid() (tid int)
//sys Getxattr(path string, attr string, dest []byte) (sz int, err error)
+//sys InitModule(moduleImage []byte, params string) (err error)
//sys InotifyAddWatch(fd int, pathname string, mask uint32) (watchdesc int, err error)
//sysnb InotifyInit1(flags int) (fd int, err error)
//sysnb InotifyRmWatch(fd int, watchdesc uint32) (success int, err error)
@@ -1256,15 +1610,18 @@ func Getpgrp() (pid int) {
//sys Llistxattr(path string, dest []byte) (sz int, err error)
//sys Lremovexattr(path string, attr string) (err error)
//sys Lsetxattr(path string, attr string, data []byte, flags int) (err error)
+//sys MemfdCreate(name string, flags int) (fd int, err error)
//sys Mkdirat(dirfd int, path string, mode uint32) (err error)
//sys Mknodat(dirfd int, path string, mode uint32, dev int) (err error)
//sys Nanosleep(time *Timespec, leftover *Timespec) (err error)
+//sys PerfEventOpen(attr *PerfEventAttr, pid int, cpu int, groupFd int, flags int) (fd int, err error)
//sys PivotRoot(newroot string, putold string) (err error) = SYS_PIVOT_ROOT
//sysnb prlimit(pid int, resource int, newlimit *Rlimit, old *Rlimit) (err error) = SYS_PRLIMIT64
//sys Prctl(option int, arg2 uintptr, arg3 uintptr, arg4 uintptr, arg5 uintptr) (err error)
+//sys Pselect(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timespec, sigmask *Sigset_t) (n int, err error) = SYS_PSELECT6
//sys read(fd int, p []byte) (n int, err error)
//sys Removexattr(path string, attr string) (err error)
-//sys Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error)
+//sys Renameat2(olddirfd int, oldpath string, newdirfd int, newpath string, flags uint) (err error)
//sys RequestKey(keyType string, description string, callback string, destRingid int) (id int, err error)
//sys Setdomainname(p []byte) (err error)
//sys Sethostname(p []byte) (err error)
@@ -1273,6 +1630,17 @@ func Getpgrp() (pid int) {
//sysnb Settimeofday(tv *Timeval) (err error)
//sys Setns(fd int, nstype int) (err error)
+// PrctlRetInt performs a prctl operation specified by option and further
+// optional arguments arg2 through arg5 depending on option. It returns a
+// non-negative integer that is returned by the prctl syscall.
+func PrctlRetInt(option int, arg2 uintptr, arg3 uintptr, arg4 uintptr, arg5 uintptr) (int, error) {
+ ret, _, err := Syscall6(SYS_PRCTL, uintptr(option), uintptr(arg2), uintptr(arg3), uintptr(arg4), uintptr(arg5), 0)
+ if err != 0 {
+ return 0, err
+ }
+ return int(ret), nil
+}
+
// issue 1435.
// On linux Setuid and Setgid only affects the current thread, not the process.
// This does not match what most callers expect so we must return an error
@@ -1286,8 +1654,14 @@ func Setgid(uid int) (err error) {
return EOPNOTSUPP
}
+func Signalfd(fd int, sigmask *Sigset_t, flags int) (newfd int, err error) {
+ return signalfd(fd, sigmask, _C__NSIG/8, flags)
+}
+
//sys Setpriority(which int, who int, prio int) (err error)
//sys Setxattr(path string, attr string, data []byte, flags int) (err error)
+//sys signalfd(fd int, sigmask *Sigset_t, maskSize uintptr, flags int) (newfd int, err error) = SYS_SIGNALFD4
+//sys Statx(dirfd int, path string, flags int, mask int, stat *Statx_t) (err error)
//sys Sync()
//sys Syncfs(fd int) (err error)
//sysnb Sysinfo(info *Sysinfo_t) (err error)
@@ -1298,11 +1672,127 @@ func Setgid(uid int) (err error) {
//sysnb Uname(buf *Utsname) (err error)
//sys Unmount(target string, flags int) (err error) = SYS_UMOUNT2
//sys Unshare(flags int) (err error)
-//sys Ustat(dev int, ubuf *Ustat_t) (err error)
//sys write(fd int, p []byte) (n int, err error)
//sys exitThread(code int) (err error) = SYS_EXIT
//sys readlen(fd int, p *byte, np int) (n int, err error) = SYS_READ
//sys writelen(fd int, p *byte, np int) (n int, err error) = SYS_WRITE
+//sys readv(fd int, iovs []Iovec) (n int, err error) = SYS_READV
+//sys writev(fd int, iovs []Iovec) (n int, err error) = SYS_WRITEV
+//sys preadv(fd int, iovs []Iovec, offs_l uintptr, offs_h uintptr) (n int, err error) = SYS_PREADV
+//sys pwritev(fd int, iovs []Iovec, offs_l uintptr, offs_h uintptr) (n int, err error) = SYS_PWRITEV
+//sys preadv2(fd int, iovs []Iovec, offs_l uintptr, offs_h uintptr, flags int) (n int, err error) = SYS_PREADV2
+//sys pwritev2(fd int, iovs []Iovec, offs_l uintptr, offs_h uintptr, flags int) (n int, err error) = SYS_PWRITEV2
+
+func bytes2iovec(bs [][]byte) []Iovec {
+ iovecs := make([]Iovec, len(bs))
+ for i, b := range bs {
+ iovecs[i].SetLen(len(b))
+ if len(b) > 0 {
+ iovecs[i].Base = &b[0]
+ } else {
+ iovecs[i].Base = (*byte)(unsafe.Pointer(&_zero))
+ }
+ }
+ return iovecs
+}
+
+// offs2lohi splits offs into its lower and upper unsigned long. On 64-bit
+// systems, hi will always be 0. On 32-bit systems, offs will be split in half.
+// preadv/pwritev chose this calling convention so they don't need to add a
+// padding-register for alignment on ARM.
+func offs2lohi(offs int64) (lo, hi uintptr) {
+ return uintptr(offs), uintptr(uint64(offs) >> SizeofLong)
+}
+
+func Readv(fd int, iovs [][]byte) (n int, err error) {
+ iovecs := bytes2iovec(iovs)
+ n, err = readv(fd, iovecs)
+ readvRacedetect(iovecs, n, err)
+ return n, err
+}
+
+func Preadv(fd int, iovs [][]byte, offset int64) (n int, err error) {
+ iovecs := bytes2iovec(iovs)
+ lo, hi := offs2lohi(offset)
+ n, err = preadv(fd, iovecs, lo, hi)
+ readvRacedetect(iovecs, n, err)
+ return n, err
+}
+
+func Preadv2(fd int, iovs [][]byte, offset int64, flags int) (n int, err error) {
+ iovecs := bytes2iovec(iovs)
+ lo, hi := offs2lohi(offset)
+ n, err = preadv2(fd, iovecs, lo, hi, flags)
+ readvRacedetect(iovecs, n, err)
+ return n, err
+}
+
+func readvRacedetect(iovecs []Iovec, n int, err error) {
+ if !raceenabled {
+ return
+ }
+ for i := 0; n > 0 && i < len(iovecs); i++ {
+ m := int(iovecs[i].Len)
+ if m > n {
+ m = n
+ }
+ n -= m
+ if m > 0 {
+ raceWriteRange(unsafe.Pointer(iovecs[i].Base), m)
+ }
+ }
+ if err == nil {
+ raceAcquire(unsafe.Pointer(&ioSync))
+ }
+}
+
+func Writev(fd int, iovs [][]byte) (n int, err error) {
+ iovecs := bytes2iovec(iovs)
+ if raceenabled {
+ raceReleaseMerge(unsafe.Pointer(&ioSync))
+ }
+ n, err = writev(fd, iovecs)
+ writevRacedetect(iovecs, n)
+ return n, err
+}
+
+func Pwritev(fd int, iovs [][]byte, offset int64) (n int, err error) {
+ iovecs := bytes2iovec(iovs)
+ if raceenabled {
+ raceReleaseMerge(unsafe.Pointer(&ioSync))
+ }
+ lo, hi := offs2lohi(offset)
+ n, err = pwritev(fd, iovecs, lo, hi)
+ writevRacedetect(iovecs, n)
+ return n, err
+}
+
+func Pwritev2(fd int, iovs [][]byte, offset int64, flags int) (n int, err error) {
+ iovecs := bytes2iovec(iovs)
+ if raceenabled {
+ raceReleaseMerge(unsafe.Pointer(&ioSync))
+ }
+ lo, hi := offs2lohi(offset)
+ n, err = pwritev2(fd, iovecs, lo, hi, flags)
+ writevRacedetect(iovecs, n)
+ return n, err
+}
+
+func writevRacedetect(iovecs []Iovec, n int) {
+ if !raceenabled {
+ return
+ }
+ for i := 0; n > 0 && i < len(iovecs); i++ {
+ m := int(iovecs[i].Len)
+ if m > n {
+ m = n
+ }
+ n -= m
+ if m > 0 {
+ raceReadRange(unsafe.Pointer(iovecs[i].Base), m)
+ }
+ }
+}
// mmap varies by architecture; see syscall_linux_*.go.
//sys munmap(addr uintptr, length uintptr) (err error)
@@ -1332,15 +1822,12 @@ func Munmap(b []byte) (err error) {
// Vmsplice splices user pages from a slice of Iovecs into a pipe specified by fd,
// using the specified flags.
func Vmsplice(fd int, iovs []Iovec, flags int) (int, error) {
- n, _, errno := Syscall6(
- SYS_VMSPLICE,
- uintptr(fd),
- uintptr(unsafe.Pointer(&iovs[0])),
- uintptr(len(iovs)),
- uintptr(flags),
- 0,
- 0,
- )
+ var p unsafe.Pointer
+ if len(iovs) > 0 {
+ p = unsafe.Pointer(&iovs[0])
+ }
+
+ n, _, errno := Syscall6(SYS_VMSPLICE, uintptr(fd), uintptr(p), uintptr(len(iovs)), uintptr(flags), 0, 0)
if errno != 0 {
return 0, syscall.Errno(errno)
}
@@ -1348,6 +1835,164 @@ func Vmsplice(fd int, iovs []Iovec, flags int) (int, error) {
return int(n), nil
}
+//sys faccessat(dirfd int, path string, mode uint32) (err error)
+
+func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) {
+ if flags & ^(AT_SYMLINK_NOFOLLOW|AT_EACCESS) != 0 {
+ return EINVAL
+ }
+
+ // The Linux kernel faccessat system call does not take any flags.
+ // The glibc faccessat implements the flags itself; see
+ // https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/faccessat.c;hb=HEAD
+ // Because people naturally expect syscall.Faccessat to act
+ // like C faccessat, we do the same.
+
+ if flags == 0 {
+ return faccessat(dirfd, path, mode)
+ }
+
+ var st Stat_t
+ if err := Fstatat(dirfd, path, &st, flags&AT_SYMLINK_NOFOLLOW); err != nil {
+ return err
+ }
+
+ mode &= 7
+ if mode == 0 {
+ return nil
+ }
+
+ var uid int
+ if flags&AT_EACCESS != 0 {
+ uid = Geteuid()
+ } else {
+ uid = Getuid()
+ }
+
+ if uid == 0 {
+ if mode&1 == 0 {
+ // Root can read and write any file.
+ return nil
+ }
+ if st.Mode&0111 != 0 {
+ // Root can execute any file that anybody can execute.
+ return nil
+ }
+ return EACCES
+ }
+
+ var fmode uint32
+ if uint32(uid) == st.Uid {
+ fmode = (st.Mode >> 6) & 7
+ } else {
+ var gid int
+ if flags&AT_EACCESS != 0 {
+ gid = Getegid()
+ } else {
+ gid = Getgid()
+ }
+
+ if uint32(gid) == st.Gid {
+ fmode = (st.Mode >> 3) & 7
+ } else {
+ fmode = st.Mode & 7
+ }
+ }
+
+ if fmode&mode == mode {
+ return nil
+ }
+
+ return EACCES
+}
+
+//sys nameToHandleAt(dirFD int, pathname string, fh *fileHandle, mountID *_C_int, flags int) (err error) = SYS_NAME_TO_HANDLE_AT
+//sys openByHandleAt(mountFD int, fh *fileHandle, flags int) (fd int, err error) = SYS_OPEN_BY_HANDLE_AT
+
+// fileHandle is the argument to nameToHandleAt and openByHandleAt. We
+// originally tried to generate it via unix/linux/types.go with "type
+// fileHandle C.struct_file_handle" but that generated empty structs
+// for mips64 and mips64le. Instead, hard code it for now (it's the
+// same everywhere else) until the mips64 generator issue is fixed.
+type fileHandle struct {
+ Bytes uint32
+ Type int32
+}
+
+// FileHandle represents the C struct file_handle used by
+// name_to_handle_at (see NameToHandleAt) and open_by_handle_at (see
+// OpenByHandleAt).
+type FileHandle struct {
+ *fileHandle
+}
+
+// NewFileHandle constructs a FileHandle.
+func NewFileHandle(handleType int32, handle []byte) FileHandle {
+ const hdrSize = unsafe.Sizeof(fileHandle{})
+ buf := make([]byte, hdrSize+uintptr(len(handle)))
+ copy(buf[hdrSize:], handle)
+ fh := (*fileHandle)(unsafe.Pointer(&buf[0]))
+ fh.Type = handleType
+ fh.Bytes = uint32(len(handle))
+ return FileHandle{fh}
+}
+
+func (fh *FileHandle) Size() int { return int(fh.fileHandle.Bytes) }
+func (fh *FileHandle) Type() int32 { return fh.fileHandle.Type }
+func (fh *FileHandle) Bytes() []byte {
+ n := fh.Size()
+ if n == 0 {
+ return nil
+ }
+ return (*[1 << 30]byte)(unsafe.Pointer(uintptr(unsafe.Pointer(&fh.fileHandle.Type)) + 4))[:n:n]
+}
+
+// NameToHandleAt wraps the name_to_handle_at system call; it obtains
+// a handle for a path name.
+func NameToHandleAt(dirfd int, path string, flags int) (handle FileHandle, mountID int, err error) {
+ var mid _C_int
+ // Try first with a small buffer, assuming the handle will
+ // only be 32 bytes.
+ size := uint32(32 + unsafe.Sizeof(fileHandle{}))
+ didResize := false
+ for {
+ buf := make([]byte, size)
+ fh := (*fileHandle)(unsafe.Pointer(&buf[0]))
+ fh.Bytes = size - uint32(unsafe.Sizeof(fileHandle{}))
+ err = nameToHandleAt(dirfd, path, fh, &mid, flags)
+ if err == EOVERFLOW {
+ if didResize {
+ // We shouldn't need to resize more than once
+ return
+ }
+ didResize = true
+ size = fh.Bytes + uint32(unsafe.Sizeof(fileHandle{}))
+ continue
+ }
+ if err != nil {
+ return
+ }
+ return FileHandle{fh}, int(mid), nil
+ }
+}
+
+// OpenByHandleAt wraps the open_by_handle_at system call; it opens a
+// file via a handle as previously returned by NameToHandleAt.
+func OpenByHandleAt(mountFD int, handle FileHandle, flags int) (fd int, err error) {
+ return openByHandleAt(mountFD, handle.fileHandle, flags)
+}
+
+// Klogset wraps the sys_syslog system call; it sets console_loglevel to
+// the value specified by arg and passes a dummy pointer to bufp.
+func Klogset(typ int, arg int) (err error) {
+ var p unsafe.Pointer
+ _, _, errno := Syscall(SYS_SYSLOG, uintptr(typ), uintptr(p), uintptr(arg))
+ if errno != 0 {
+ return errnoErr(errno)
+ }
+ return nil
+}
+
/*
* Unimplemented
*/
@@ -1355,23 +2000,14 @@ func Vmsplice(fd int, iovs []Iovec, flags int) (int, error) {
// Alarm
// ArchPrctl
// Brk
-// Capget
-// Capset
-// ClockGetres
// ClockNanosleep
// ClockSettime
// Clone
-// CreateModule
-// DeleteModule
// EpollCtlOld
// EpollPwait
// EpollWaitOld
// Execve
-// Fgetxattr
-// Flistxattr
// Fork
-// Fremovexattr
-// Fsetxattr
// Futex
// GetKernelSyms
// GetMempolicy
@@ -1405,13 +2041,11 @@ func Vmsplice(fd int, iovs []Iovec, flags int) (int, error) {
// Msgget
// Msgrcv
// Msgsnd
-// Newfstatat
// Nfsservctl
// Personality
// Pselect6
// Ptrace
// Putpmsg
-// QueryModule
// Quotactl
// Readahead
// Readv
@@ -1426,11 +2060,9 @@ func Vmsplice(fd int, iovs []Iovec, flags int) (int, error) {
// RtSigtimedwait
// SchedGetPriorityMax
// SchedGetPriorityMin
-// SchedGetaffinity
// SchedGetparam
// SchedGetscheduler
// SchedRrGetInterval
-// SchedSetaffinity
// SchedSetparam
// SchedYield
// Security
@@ -1447,7 +2079,6 @@ func Vmsplice(fd int, iovs []Iovec, flags int) (int, error) {
// Shmdt
// Shmget
// Sigaltstack
-// Signalfd
// Swapoff
// Swapon
// Sysfs
diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_386.go b/vendor/golang.org/x/sys/unix/syscall_linux_386.go
index f4c826a..e7fa665 100644
--- a/vendor/golang.org/x/sys/unix/syscall_linux_386.go
+++ b/vendor/golang.org/x/sys/unix/syscall_linux_386.go
@@ -10,23 +10,15 @@
package unix
import (
- "syscall"
"unsafe"
)
-func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
-
-func NsecToTimespec(nsec int64) (ts Timespec) {
- ts.Sec = int32(nsec / 1e9)
- ts.Nsec = int32(nsec % 1e9)
- return
+func setTimespec(sec, nsec int64) Timespec {
+ return Timespec{Sec: int32(sec), Nsec: int32(nsec)}
}
-func NsecToTimeval(nsec int64) (tv Timeval) {
- nsec += 999 // round up to microsecond
- tv.Sec = int32(nsec / 1e9)
- tv.Usec = int32(nsec % 1e9 / 1e3)
- return
+func setTimeval(sec, usec int64) Timeval {
+ return Timeval{Sec: int32(sec), Usec: int32(usec)}
}
//sysnb pipe(p *[2]_C_int) (err error)
@@ -58,9 +50,12 @@ func Pipe2(p []int, flags int) (err error) {
// 64-bit file system and 32-bit uid calls
// (386 default is 32-bit file system and 16-bit uid).
//sys Dup2(oldfd int, newfd int) (err error)
+//sysnb EpollCreate(size int) (fd int, err error)
+//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error)
//sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64_64
//sys Fchown(fd int, uid int, gid int) (err error) = SYS_FCHOWN32
//sys Fstat(fd int, stat *Stat_t) (err error) = SYS_FSTAT64
+//sys Fstatat(dirfd int, path string, stat *Stat_t, flags int) (err error) = SYS_FSTATAT64
//sys Ftruncate(fd int, length int64) (err error) = SYS_FTRUNCATE64
//sysnb Getegid() (egid int) = SYS_GETEGID32
//sysnb Geteuid() (euid int) = SYS_GETEUID32
@@ -73,6 +68,7 @@ func Pipe2(p []int, flags int) (err error) {
//sys Lstat(path string, stat *Stat_t) (err error) = SYS_LSTAT64
//sys Pread(fd int, p []byte, offset int64) (n int, err error) = SYS_PREAD64
//sys Pwrite(fd int, p []byte, offset int64) (n int, err error) = SYS_PWRITE64
+//sys Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error)
//sys sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) = SYS_SENDFILE64
//sys Setfsgid(gid int) (err error) = SYS_SETFSGID32
//sys Setfsuid(uid int) (err error) = SYS_SETFSUID32
@@ -84,12 +80,12 @@ func Pipe2(p []int, flags int) (err error) {
//sys Stat(path string, stat *Stat_t) (err error) = SYS_STAT64
//sys SyncFileRange(fd int, off int64, n int64, flags int) (err error)
//sys Truncate(path string, length int64) (err error) = SYS_TRUNCATE64
+//sys Ustat(dev int, ubuf *Ustat_t) (err error)
//sysnb getgroups(n int, list *_Gid_t) (nn int, err error) = SYS_GETGROUPS32
//sysnb setgroups(n int, list *_Gid_t) (err error) = SYS_SETGROUPS32
//sys Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err error) = SYS__NEWSELECT
//sys mmap2(addr uintptr, length uintptr, prot int, flags int, fd int, pageOffset uintptr) (xaddr uintptr, err error)
-//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error)
//sys Pause() (err error)
func mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, err error) {
@@ -163,10 +159,6 @@ func Setrlimit(resource int, rlim *Rlimit) (err error) {
return setrlimit(resource, &rl)
}
-// Underlying system call writes to newoffset via pointer.
-// Implemented in assembly to avoid allocation.
-func seek(fd int, offset int64, whence int) (newoffset int64, err syscall.Errno)
-
func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
newoffset, errno := seek(fd, offset, whence)
if errno != 0 {
@@ -175,17 +167,17 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
return newoffset, nil
}
-// Vsyscalls on amd64.
+//sys futimesat(dirfd int, path string, times *[2]Timeval) (err error)
//sysnb Gettimeofday(tv *Timeval) (err error)
//sysnb Time(t *Time_t) (tt Time_t, err error)
-
//sys Utime(path string, buf *Utimbuf) (err error)
+//sys utimes(path string, times *[2]Timeval) (err error)
// On x86 Linux, all the socket calls go through an extra indirection,
// I think because the 5-register system call interface can't handle
-// the 6-argument calls like sendto and recvfrom. Instead the
+// the 6-argument calls like sendto and recvfrom. Instead the
// arguments to the underlying system call are the number below
-// and a pointer to an array of uintptr. We hide the pointer in the
+// and a pointer to an array of uintptr. We hide the pointer in the
// socketcall assembly to avoid allocation on every system call.
const (
@@ -212,9 +204,6 @@ const (
_SENDMMSG = 20
)
-func socketcall(call int, a0, a1, a2, a3, a4, a5 uintptr) (n int, err syscall.Errno)
-func rawsocketcall(call int, a0, a1, a2, a3, a4, a5 uintptr) (n int, err syscall.Errno)
-
func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
fd, e := socketcall(_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), 0, 0, 0)
if e != 0 {
@@ -383,6 +372,10 @@ func (msghdr *Msghdr) SetControllen(length int) {
msghdr.Controllen = uint32(length)
}
+func (msghdr *Msghdr) SetIovlen(length int) {
+ msghdr.Iovlen = uint32(length)
+}
+
func (cmsg *Cmsghdr) SetLen(length int) {
cmsg.Len = uint32(length)
}
diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_amd64.go b/vendor/golang.org/x/sys/unix/syscall_linux_amd64.go
index 0715200..088ce0f 100644
--- a/vendor/golang.org/x/sys/unix/syscall_linux_amd64.go
+++ b/vendor/golang.org/x/sys/unix/syscall_linux_amd64.go
@@ -7,10 +7,12 @@
package unix
//sys Dup2(oldfd int, newfd int) (err error)
+//sysnb EpollCreate(size int) (fd int, err error)
//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error)
//sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64
//sys Fchown(fd int, uid int, gid int) (err error)
//sys Fstat(fd int, stat *Stat_t) (err error)
+//sys Fstatat(dirfd int, path string, stat *Stat_t, flags int) (err error) = SYS_NEWFSTATAT
//sys Fstatfs(fd int, buf *Statfs_t) (err error)
//sys Ftruncate(fd int, length int64) (err error)
//sysnb Getegid() (egid int)
@@ -18,17 +20,40 @@ package unix
//sysnb Getgid() (gid int)
//sysnb Getrlimit(resource int, rlim *Rlimit) (err error)
//sysnb Getuid() (uid int)
-//sysnb InotifyInit() (fd int, err error)
+//sysnb inotifyInit() (fd int, err error)
+
+func InotifyInit() (fd int, err error) {
+ // First try inotify_init1, because Android's seccomp policy blocks the latter.
+ fd, err = InotifyInit1(0)
+ if err == ENOSYS {
+ fd, err = inotifyInit()
+ }
+ return
+}
+
//sys Ioperm(from int, num int, on int) (err error)
//sys Iopl(level int) (err error)
//sys Lchown(path string, uid int, gid int) (err error)
//sys Listen(s int, n int) (err error)
-//sys Lstat(path string, stat *Stat_t) (err error)
+
+func Lstat(path string, stat *Stat_t) (err error) {
+ return Fstatat(AT_FDCWD, path, stat, AT_SYMLINK_NOFOLLOW)
+}
+
//sys Pause() (err error)
//sys Pread(fd int, p []byte, offset int64) (n int, err error) = SYS_PREAD64
//sys Pwrite(fd int, p []byte, offset int64) (n int, err error) = SYS_PWRITE64
+//sys Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error)
//sys Seek(fd int, offset int64, whence int) (off int64, err error) = SYS_LSEEK
-//sys Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err error)
+
+func Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err error) {
+ var ts *Timespec
+ if timeout != nil {
+ ts = &Timespec{Sec: timeout.Sec, Nsec: timeout.Usec * 1000}
+ }
+ return Pselect(nfd, r, w, e, ts, nil)
+}
+
//sys sendfile(outfd int, infd int, offset *int64, count int) (written int, err error)
//sys Setfsgid(gid int) (err error)
//sys Setfsuid(uid int) (err error)
@@ -39,10 +64,16 @@ package unix
//sysnb Setreuid(ruid int, euid int) (err error)
//sys Shutdown(fd int, how int) (err error)
//sys Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, err error)
-//sys Stat(path string, stat *Stat_t) (err error)
+
+func Stat(path string, stat *Stat_t) (err error) {
+ // Use fstatat, because Android's seccomp policy blocks stat.
+ return Fstatat(AT_FDCWD, path, stat, 0)
+}
+
//sys Statfs(path string, buf *Statfs_t) (err error)
//sys SyncFileRange(fd int, off int64, n int64, flags int) (err error)
//sys Truncate(path string, length int64) (err error)
+//sys Ustat(dev int, ubuf *Ustat_t) (err error)
//sys accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error)
//sys accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int, err error)
//sys bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error)
@@ -61,6 +92,8 @@ package unix
//sys sendmsg(s int, msg *Msghdr, flags int) (n int, err error)
//sys mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, err error)
+//sys futimesat(dirfd int, path string, times *[2]Timeval) (err error)
+
func Gettimeofday(tv *Timeval) (err error) {
errno := gettimeofday(tv)
if errno != 0 {
@@ -82,20 +115,14 @@ func Time(t *Time_t) (tt Time_t, err error) {
}
//sys Utime(path string, buf *Utimbuf) (err error)
+//sys utimes(path string, times *[2]Timeval) (err error)
-func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
-
-func NsecToTimespec(nsec int64) (ts Timespec) {
- ts.Sec = nsec / 1e9
- ts.Nsec = nsec % 1e9
- return
+func setTimespec(sec, nsec int64) Timespec {
+ return Timespec{Sec: sec, Nsec: nsec}
}
-func NsecToTimeval(nsec int64) (tv Timeval) {
- nsec += 999 // round up to microsecond
- tv.Sec = nsec / 1e9
- tv.Usec = nsec % 1e9 / 1e3
- return
+func setTimeval(sec, usec int64) Timeval {
+ return Timeval{Sec: sec, Usec: usec}
}
//sysnb pipe(p *[2]_C_int) (err error)
@@ -136,6 +163,10 @@ func (msghdr *Msghdr) SetControllen(length int) {
msghdr.Controllen = uint64(length)
}
+func (msghdr *Msghdr) SetIovlen(length int) {
+ msghdr.Iovlen = uint64(length)
+}
+
func (cmsg *Cmsghdr) SetLen(length int) {
cmsg.Len = uint64(length)
}
@@ -148,3 +179,16 @@ func Poll(fds []PollFd, timeout int) (n int, err error) {
}
return poll(&fds[0], len(fds), timeout)
}
+
+//sys kexecFileLoad(kernelFd int, initrdFd int, cmdlineLen int, cmdline string, flags int) (err error)
+
+func KexecFileLoad(kernelFd int, initrdFd int, cmdline string, flags int) error {
+ cmdlineLen := len(cmdline)
+ if cmdlineLen > 0 {
+ // Account for the additional NULL byte added by
+ // BytePtrFromString in kexecFileLoad. The kexec_file_load
+ // syscall expects a NULL-terminated string.
+ cmdlineLen++
+ }
+ return kexecFileLoad(kernelFd, initrdFd, cmdlineLen, cmdline, flags)
+}
diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_arm.go b/vendor/golang.org/x/sys/unix/syscall_linux_arm.go
index 2b79c84..11930fc 100644
--- a/vendor/golang.org/x/sys/unix/syscall_linux_arm.go
+++ b/vendor/golang.org/x/sys/unix/syscall_linux_arm.go
@@ -11,27 +11,26 @@ import (
"unsafe"
)
-func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
-
-func NsecToTimespec(nsec int64) (ts Timespec) {
- ts.Sec = int32(nsec / 1e9)
- ts.Nsec = int32(nsec % 1e9)
- return
+func setTimespec(sec, nsec int64) Timespec {
+ return Timespec{Sec: int32(sec), Nsec: int32(nsec)}
}
-func NsecToTimeval(nsec int64) (tv Timeval) {
- nsec += 999 // round up to microsecond
- tv.Sec = int32(nsec / 1e9)
- tv.Usec = int32(nsec % 1e9 / 1e3)
- return
+func setTimeval(sec, usec int64) Timeval {
+ return Timeval{Sec: int32(sec), Usec: int32(usec)}
}
+//sysnb pipe(p *[2]_C_int) (err error)
+
func Pipe(p []int) (err error) {
if len(p) != 2 {
return EINVAL
}
var pp [2]_C_int
+ // Try pipe2 first for Android O, then try pipe for kernel 2.6.23.
err = pipe2(&pp, 0)
+ if err == ENOSYS {
+ err = pipe(&pp)
+ }
p[0] = int(pp[0])
p[1] = int(pp[1])
return
@@ -82,8 +81,11 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
// 64-bit file system and 32-bit uid calls
// (16-bit uid calls are not always supported in newer kernels)
//sys Dup2(oldfd int, newfd int) (err error)
+//sysnb EpollCreate(size int) (fd int, err error)
+//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error)
//sys Fchown(fd int, uid int, gid int) (err error) = SYS_FCHOWN32
//sys Fstat(fd int, stat *Stat_t) (err error) = SYS_FSTAT64
+//sys Fstatat(dirfd int, path string, stat *Stat_t, flags int) (err error) = SYS_FSTATAT64
//sysnb Getegid() (egid int) = SYS_GETEGID32
//sysnb Geteuid() (euid int) = SYS_GETEUID32
//sysnb Getgid() (gid int) = SYS_GETGID32
@@ -92,6 +94,8 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
//sys Lchown(path string, uid int, gid int) (err error) = SYS_LCHOWN32
//sys Listen(s int, n int) (err error)
//sys Lstat(path string, stat *Stat_t) (err error) = SYS_LSTAT64
+//sys Pause() (err error)
+//sys Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error)
//sys sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) = SYS_SENDFILE64
//sys Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err error) = SYS__NEWSELECT
//sys Setfsgid(gid int) (err error) = SYS_SETFSGID32
@@ -103,11 +107,10 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
//sys Shutdown(fd int, how int) (err error)
//sys Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int, err error)
//sys Stat(path string, stat *Stat_t) (err error) = SYS_STAT64
+//sys Ustat(dev int, ubuf *Ustat_t) (err error)
-// Vsyscalls on amd64.
+//sys futimesat(dirfd int, path string, times *[2]Timeval) (err error)
//sysnb Gettimeofday(tv *Timeval) (err error)
-//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error)
-//sys Pause() (err error)
func Time(t *Time_t) (Time_t, error) {
var tv Timeval
@@ -129,6 +132,8 @@ func Utime(path string, buf *Utimbuf) error {
return Utimes(path, tv)
}
+//sys utimes(path string, times *[2]Timeval) (err error)
+
//sys Pread(fd int, p []byte, offset int64) (n int, err error) = SYS_PREAD64
//sys Pwrite(fd int, p []byte, offset int64) (n int, err error) = SYS_PWRITE64
//sys Truncate(path string, length int64) (err error) = SYS_TRUNCATE64
@@ -247,6 +252,10 @@ func (msghdr *Msghdr) SetControllen(length int) {
msghdr.Controllen = uint32(length)
}
+func (msghdr *Msghdr) SetIovlen(length int) {
+ msghdr.Iovlen = uint32(length)
+}
+
func (cmsg *Cmsghdr) SetLen(length int) {
cmsg.Len = uint32(length)
}
@@ -259,3 +268,24 @@ func Poll(fds []PollFd, timeout int) (n int, err error) {
}
return poll(&fds[0], len(fds), timeout)
}
+
+//sys armSyncFileRange(fd int, flags int, off int64, n int64) (err error) = SYS_ARM_SYNC_FILE_RANGE
+
+func SyncFileRange(fd int, off int64, n int64, flags int) error {
+ // The sync_file_range and arm_sync_file_range syscalls differ only in the
+ // order of their arguments.
+ return armSyncFileRange(fd, flags, off, n)
+}
+
+//sys kexecFileLoad(kernelFd int, initrdFd int, cmdlineLen int, cmdline string, flags int) (err error)
+
+func KexecFileLoad(kernelFd int, initrdFd int, cmdline string, flags int) error {
+ cmdlineLen := len(cmdline)
+ if cmdlineLen > 0 {
+ // Account for the additional NULL byte added by
+ // BytePtrFromString in kexecFileLoad. The kexec_file_load
+ // syscall expects a NULL-terminated string.
+ cmdlineLen++
+ }
+ return kexecFileLoad(kernelFd, initrdFd, cmdlineLen, cmdline, flags)
+}
diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_arm64.go b/vendor/golang.org/x/sys/unix/syscall_linux_arm64.go
index 68cc975..251e2d9 100644
--- a/vendor/golang.org/x/sys/unix/syscall_linux_arm64.go
+++ b/vendor/golang.org/x/sys/unix/syscall_linux_arm64.go
@@ -6,7 +6,17 @@
package unix
+import "unsafe"
+
+func EpollCreate(size int) (fd int, err error) {
+ if size <= 0 {
+ return -1, EINVAL
+ }
+ return EpollCreate1(0)
+}
+
//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) = SYS_EPOLL_PWAIT
+//sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64
//sys Fchown(fd int, uid int, gid int) (err error)
//sys Fstat(fd int, stat *Stat_t) (err error)
//sys Fstatat(fd int, path string, stat *Stat_t, flags int) (err error)
@@ -20,8 +30,17 @@ package unix
//sys Listen(s int, n int) (err error)
//sys Pread(fd int, p []byte, offset int64) (n int, err error) = SYS_PREAD64
//sys Pwrite(fd int, p []byte, offset int64) (n int, err error) = SYS_PWRITE64
+//sys Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error)
//sys Seek(fd int, offset int64, whence int) (off int64, err error) = SYS_LSEEK
-//sys Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err error) = SYS_PSELECT6
+
+func Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err error) {
+ var ts *Timespec
+ if timeout != nil {
+ ts = &Timespec{Sec: timeout.Sec, Nsec: timeout.Usec * 1000}
+ }
+ return Pselect(nfd, r, w, e, ts, nil)
+}
+
//sys sendfile(outfd int, infd int, offset *int64, count int) (written int, err error)
//sys Setfsgid(gid int) (err error)
//sys Setfsuid(uid int) (err error)
@@ -48,6 +67,11 @@ func Lstat(path string, stat *Stat_t) (err error) {
//sys Statfs(path string, buf *Statfs_t) (err error)
//sys SyncFileRange(fd int, off int64, n int64, flags int) (err error)
//sys Truncate(path string, length int64) (err error)
+
+func Ustat(dev int, ubuf *Ustat_t) (err error) {
+ return ENOSYS
+}
+
//sys accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error)
//sys accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int, err error)
//sys bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error)
@@ -68,19 +92,24 @@ func Lstat(path string, stat *Stat_t) (err error) {
//sysnb Gettimeofday(tv *Timeval) (err error)
-func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
-
-func NsecToTimespec(nsec int64) (ts Timespec) {
- ts.Sec = nsec / 1e9
- ts.Nsec = nsec % 1e9
- return
+func setTimespec(sec, nsec int64) Timespec {
+ return Timespec{Sec: sec, Nsec: nsec}
}
-func NsecToTimeval(nsec int64) (tv Timeval) {
- nsec += 999 // round up to microsecond
- tv.Sec = nsec / 1e9
- tv.Usec = nsec % 1e9 / 1e3
- return
+func setTimeval(sec, usec int64) Timeval {
+ return Timeval{Sec: sec, Usec: usec}
+}
+
+func futimesat(dirfd int, path string, tv *[2]Timeval) (err error) {
+ if tv == nil {
+ return utimensat(dirfd, path, nil, 0)
+ }
+
+ ts := []Timespec{
+ NsecToTimespec(TimevalToNsec(tv[0])),
+ NsecToTimespec(TimevalToNsec(tv[1])),
+ }
+ return utimensat(dirfd, path, (*[2]Timespec)(unsafe.Pointer(&ts[0])), 0)
}
func Time(t *Time_t) (Time_t, error) {
@@ -103,6 +132,18 @@ func Utime(path string, buf *Utimbuf) error {
return Utimes(path, tv)
}
+func utimes(path string, tv *[2]Timeval) (err error) {
+ if tv == nil {
+ return utimensat(AT_FDCWD, path, nil, 0)
+ }
+
+ ts := []Timespec{
+ NsecToTimespec(TimevalToNsec(tv[0])),
+ NsecToTimespec(TimevalToNsec(tv[1])),
+ }
+ return utimensat(AT_FDCWD, path, (*[2]Timespec)(unsafe.Pointer(&ts[0])), 0)
+}
+
func Pipe(p []int) (err error) {
if len(p) != 2 {
return EINVAL
@@ -139,6 +180,10 @@ func (msghdr *Msghdr) SetControllen(length int) {
msghdr.Controllen = uint64(length)
}
+func (msghdr *Msghdr) SetIovlen(length int) {
+ msghdr.Iovlen = uint64(length)
+}
+
func (cmsg *Cmsghdr) SetLen(length int) {
cmsg.Len = uint64(length)
}
@@ -151,30 +196,11 @@ func Dup2(oldfd int, newfd int) (err error) {
return Dup3(oldfd, newfd, 0)
}
-func Pause() (err error) {
- _, _, e1 := Syscall6(SYS_PPOLL, 0, 0, 0, 0, 0, 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
+func Pause() error {
+ _, err := ppoll(nil, 0, nil, nil)
+ return err
}
-// TODO(dfc): constants that should be in zsysnum_linux_arm64.go, remove
-// these when the deprecated syscalls that the syscall package relies on
-// are removed.
-const (
- SYS_GETPGRP = 1060
- SYS_UTIMES = 1037
- SYS_FUTIMESAT = 1066
- SYS_PAUSE = 1061
- SYS_USTAT = 1070
- SYS_UTIME = 1063
- SYS_LCHOWN = 1032
- SYS_TIME = 1062
- SYS_EPOLL_CREATE = 1042
- SYS_EPOLL_WAIT = 1069
-)
-
func Poll(fds []PollFd, timeout int) (n int, err error) {
var ts *Timespec
if timeout >= 0 {
@@ -186,3 +212,16 @@ func Poll(fds []PollFd, timeout int) (n int, err error) {
}
return ppoll(&fds[0], len(fds), ts, nil)
}
+
+//sys kexecFileLoad(kernelFd int, initrdFd int, cmdlineLen int, cmdline string, flags int) (err error)
+
+func KexecFileLoad(kernelFd int, initrdFd int, cmdline string, flags int) error {
+ cmdlineLen := len(cmdline)
+ if cmdlineLen > 0 {
+ // Account for the additional NULL byte added by
+ // BytePtrFromString in kexecFileLoad. The kexec_file_load
+ // syscall expects a NULL-terminated string.
+ cmdlineLen++
+ }
+ return kexecFileLoad(kernelFd, initrdFd, cmdlineLen, cmdline, flags)
+}
diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_gc.go b/vendor/golang.org/x/sys/unix/syscall_linux_gc.go
new file mode 100644
index 0000000..c26e6ec
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/syscall_linux_gc.go
@@ -0,0 +1,14 @@
+// Copyright 2018 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 linux,!gccgo
+
+package unix
+
+// SyscallNoError may be used instead of Syscall for syscalls that don't fail.
+func SyscallNoError(trap, a1, a2, a3 uintptr) (r1, r2 uintptr)
+
+// RawSyscallNoError may be used instead of RawSyscall for syscalls that don't
+// fail.
+func RawSyscallNoError(trap, a1, a2, a3 uintptr) (r1, r2 uintptr)
diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_gc_386.go b/vendor/golang.org/x/sys/unix/syscall_linux_gc_386.go
new file mode 100644
index 0000000..070bd38
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/syscall_linux_gc_386.go
@@ -0,0 +1,16 @@
+// Copyright 2018 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 linux,!gccgo,386
+
+package unix
+
+import "syscall"
+
+// Underlying system call writes to newoffset via pointer.
+// Implemented in assembly to avoid allocation.
+func seek(fd int, offset int64, whence int) (newoffset int64, err syscall.Errno)
+
+func socketcall(call int, a0, a1, a2, a3, a4, a5 uintptr) (n int, err syscall.Errno)
+func rawsocketcall(call int, a0, a1, a2, a3, a4, a5 uintptr) (n int, err syscall.Errno)
diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_gccgo_386.go b/vendor/golang.org/x/sys/unix/syscall_linux_gccgo_386.go
new file mode 100644
index 0000000..308eb7a
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/syscall_linux_gccgo_386.go
@@ -0,0 +1,30 @@
+// Copyright 2018 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 linux,gccgo,386
+
+package unix
+
+import (
+ "syscall"
+ "unsafe"
+)
+
+func seek(fd int, offset int64, whence int) (int64, syscall.Errno) {
+ var newoffset int64
+ offsetLow := uint32(offset & 0xffffffff)
+ offsetHigh := uint32((offset >> 32) & 0xffffffff)
+ _, _, err := Syscall6(SYS__LLSEEK, uintptr(fd), uintptr(offsetHigh), uintptr(offsetLow), uintptr(unsafe.Pointer(&newoffset)), uintptr(whence), 0)
+ return newoffset, err
+}
+
+func socketcall(call int, a0, a1, a2, a3, a4, a5 uintptr) (int, syscall.Errno) {
+ fd, _, err := Syscall(SYS_SOCKETCALL, uintptr(call), uintptr(unsafe.Pointer(&a0)), 0)
+ return int(fd), err
+}
+
+func rawsocketcall(call int, a0, a1, a2, a3, a4, a5 uintptr) (int, syscall.Errno) {
+ fd, _, err := RawSyscall(SYS_SOCKETCALL, uintptr(call), uintptr(unsafe.Pointer(&a0)), 0)
+ return int(fd), err
+}
diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_gccgo_arm.go b/vendor/golang.org/x/sys/unix/syscall_linux_gccgo_arm.go
new file mode 100644
index 0000000..aa7fc9e
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/syscall_linux_gccgo_arm.go
@@ -0,0 +1,20 @@
+// Copyright 2018 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 linux,gccgo,arm
+
+package unix
+
+import (
+ "syscall"
+ "unsafe"
+)
+
+func seek(fd int, offset int64, whence int) (int64, syscall.Errno) {
+ var newoffset int64
+ offsetLow := uint32(offset & 0xffffffff)
+ offsetHigh := uint32((offset >> 32) & 0xffffffff)
+ _, _, err := Syscall6(SYS__LLSEEK, uintptr(fd), uintptr(offsetHigh), uintptr(offsetLow), uintptr(unsafe.Pointer(&newoffset)), uintptr(whence), 0)
+ return newoffset, err
+}
diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_mips64x.go b/vendor/golang.org/x/sys/unix/syscall_linux_mips64x.go
index 977df44..7562fe9 100644
--- a/vendor/golang.org/x/sys/unix/syscall_linux_mips64x.go
+++ b/vendor/golang.org/x/sys/unix/syscall_linux_mips64x.go
@@ -8,7 +8,9 @@
package unix
//sys Dup2(oldfd int, newfd int) (err error)
+//sysnb EpollCreate(size int) (fd int, err error)
//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error)
+//sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64
//sys Fchown(fd int, uid int, gid int) (err error)
//sys Fstatfs(fd int, buf *Statfs_t) (err error)
//sys Ftruncate(fd int, length int64) (err error)
@@ -22,8 +24,17 @@ package unix
//sys Pause() (err error)
//sys Pread(fd int, p []byte, offset int64) (n int, err error) = SYS_PREAD64
//sys Pwrite(fd int, p []byte, offset int64) (n int, err error) = SYS_PWRITE64
+//sys Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error)
//sys Seek(fd int, offset int64, whence int) (off int64, err error) = SYS_LSEEK
-//sys Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err error) = SYS_PSELECT6
+
+func Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err error) {
+ var ts *Timespec
+ if timeout != nil {
+ ts = &Timespec{Sec: timeout.Sec, Nsec: timeout.Usec * 1000}
+ }
+ return Pselect(nfd, r, w, e, ts, nil)
+}
+
//sys sendfile(outfd int, infd int, offset *int64, count int) (written int, err error)
//sys Setfsgid(gid int) (err error)
//sys Setfsuid(uid int) (err error)
@@ -37,6 +48,7 @@ package unix
//sys Statfs(path string, buf *Statfs_t) (err error)
//sys SyncFileRange(fd int, off int64, n int64, flags int) (err error)
//sys Truncate(path string, length int64) (err error)
+//sys Ustat(dev int, ubuf *Ustat_t) (err error)
//sys accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error)
//sys accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int, err error)
//sys bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error)
@@ -55,6 +67,7 @@ package unix
//sys sendmsg(s int, msg *Msghdr, flags int) (n int, err error)
//sys mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, err error)
+//sys futimesat(dirfd int, path string, times *[2]Timeval) (err error)
//sysnb Gettimeofday(tv *Timeval) (err error)
func Time(t *Time_t) (tt Time_t, err error) {
@@ -70,20 +83,14 @@ func Time(t *Time_t) (tt Time_t, err error) {
}
//sys Utime(path string, buf *Utimbuf) (err error)
+//sys utimes(path string, times *[2]Timeval) (err error)
-func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
-
-func NsecToTimespec(nsec int64) (ts Timespec) {
- ts.Sec = nsec / 1e9
- ts.Nsec = nsec % 1e9
- return
+func setTimespec(sec, nsec int64) Timespec {
+ return Timespec{Sec: sec, Nsec: nsec}
}
-func NsecToTimeval(nsec int64) (tv Timeval) {
- nsec += 999 // round up to microsecond
- tv.Sec = nsec / 1e9
- tv.Usec = nsec % 1e9 / 1e3
- return
+func setTimeval(sec, usec int64) Timeval {
+ return Timeval{Sec: sec, Usec: usec}
}
func Pipe(p []int) (err error) {
@@ -141,6 +148,7 @@ type stat_t struct {
}
//sys fstat(fd int, st *stat_t) (err error)
+//sys fstatat(dirfd int, path string, st *stat_t, flags int) (err error) = SYS_NEWFSTATAT
//sys lstat(path string, st *stat_t) (err error)
//sys stat(path string, st *stat_t) (err error)
@@ -151,6 +159,13 @@ func Fstat(fd int, s *Stat_t) (err error) {
return
}
+func Fstatat(dirfd int, path string, s *Stat_t, flags int) (err error) {
+ st := &stat_t{}
+ err = fstatat(dirfd, path, st, flags)
+ fillStat_t(s, st)
+ return
+}
+
func Lstat(path string, s *Stat_t) (err error) {
st := &stat_t{}
err = lstat(path, st)
@@ -193,6 +208,10 @@ func (msghdr *Msghdr) SetControllen(length int) {
msghdr.Controllen = uint64(length)
}
+func (msghdr *Msghdr) SetIovlen(length int) {
+ msghdr.Iovlen = uint64(length)
+}
+
func (cmsg *Cmsghdr) SetLen(length int) {
cmsg.Len = uint64(length)
}
diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_mipsx.go b/vendor/golang.org/x/sys/unix/syscall_linux_mipsx.go
index 25a5a0d..a939ff8 100644
--- a/vendor/golang.org/x/sys/unix/syscall_linux_mipsx.go
+++ b/vendor/golang.org/x/sys/unix/syscall_linux_mipsx.go
@@ -15,6 +15,9 @@ import (
func Syscall9(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno)
//sys Dup2(oldfd int, newfd int) (err error)
+//sysnb EpollCreate(size int) (fd int, err error)
+//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error)
+//sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64
//sys Fchown(fd int, uid int, gid int) (err error)
//sys Ftruncate(fd int, length int64) (err error) = SYS_FTRUNCATE64
//sysnb Getegid() (egid int)
@@ -25,6 +28,7 @@ func Syscall9(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr,
//sys Listen(s int, n int) (err error)
//sys Pread(fd int, p []byte, offset int64) (n int, err error) = SYS_PREAD64
//sys Pwrite(fd int, p []byte, offset int64) (n int, err error) = SYS_PWRITE64
+//sys Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error)
//sys Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err error) = SYS__NEWSELECT
//sys sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) = SYS_SENDFILE64
//sys Setfsgid(gid int) (err error)
@@ -32,13 +36,12 @@ func Syscall9(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr,
//sysnb Setregid(rgid int, egid int) (err error)
//sysnb Setresgid(rgid int, egid int, sgid int) (err error)
//sysnb Setresuid(ruid int, euid int, suid int) (err error)
-
//sysnb Setreuid(ruid int, euid int) (err error)
//sys Shutdown(fd int, how int) (err error)
-//sys Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, err error)
-
+//sys Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int, err error)
//sys SyncFileRange(fd int, off int64, n int64, flags int) (err error)
//sys Truncate(path string, length int64) (err error) = SYS_TRUNCATE64
+//sys Ustat(dev int, ubuf *Ustat_t) (err error)
//sys accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error)
//sys accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int, err error)
//sys bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error)
@@ -60,15 +63,17 @@ func Syscall9(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr,
//sys Ioperm(from int, num int, on int) (err error)
//sys Iopl(level int) (err error)
+//sys futimesat(dirfd int, path string, times *[2]Timeval) (err error)
//sysnb Gettimeofday(tv *Timeval) (err error)
//sysnb Time(t *Time_t) (tt Time_t, err error)
+//sys Utime(path string, buf *Utimbuf) (err error)
+//sys utimes(path string, times *[2]Timeval) (err error)
//sys Lstat(path string, stat *Stat_t) (err error) = SYS_LSTAT64
//sys Fstat(fd int, stat *Stat_t) (err error) = SYS_FSTAT64
+//sys Fstatat(dirfd int, path string, stat *Stat_t, flags int) (err error) = SYS_FSTATAT64
//sys Stat(path string, stat *Stat_t) (err error) = SYS_STAT64
-//sys Utime(path string, buf *Utimbuf) (err error)
-//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error)
//sys Pause() (err error)
func Fstatfs(fd int, buf *Statfs_t) (err error) {
@@ -99,19 +104,12 @@ func Seek(fd int, offset int64, whence int) (off int64, err error) {
return
}
-func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
-
-func NsecToTimespec(nsec int64) (ts Timespec) {
- ts.Sec = int32(nsec / 1e9)
- ts.Nsec = int32(nsec % 1e9)
- return
+func setTimespec(sec, nsec int64) Timespec {
+ return Timespec{Sec: int32(sec), Nsec: int32(nsec)}
}
-func NsecToTimeval(nsec int64) (tv Timeval) {
- nsec += 999 // round up to microsecond
- tv.Sec = int32(nsec / 1e9)
- tv.Usec = int32(nsec % 1e9 / 1e3)
- return
+func setTimeval(sec, usec int64) Timeval {
+ return Timeval{Sec: int32(sec), Usec: int32(usec)}
}
//sysnb pipe2(p *[2]_C_int, flags int) (err error)
@@ -127,14 +125,13 @@ func Pipe2(p []int, flags int) (err error) {
return
}
+//sysnb pipe() (p1 int, p2 int, err error)
+
func Pipe(p []int) (err error) {
if len(p) != 2 {
return EINVAL
}
- var pp [2]_C_int
- err = pipe2(&pp, 0)
- p[0] = int(pp[0])
- p[1] = int(pp[1])
+ p[0], p[1], err = pipe()
return
}
@@ -223,6 +220,10 @@ func (msghdr *Msghdr) SetControllen(length int) {
msghdr.Controllen = uint32(length)
}
+func (msghdr *Msghdr) SetIovlen(length int) {
+ msghdr.Iovlen = uint32(length)
+}
+
func (cmsg *Cmsghdr) SetLen(length int) {
cmsg.Len = uint32(length)
}
diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_ppc64x.go b/vendor/golang.org/x/sys/unix/syscall_linux_ppc64x.go
index a4a8e4e..28d6d0f 100644
--- a/vendor/golang.org/x/sys/unix/syscall_linux_ppc64x.go
+++ b/vendor/golang.org/x/sys/unix/syscall_linux_ppc64x.go
@@ -7,10 +7,13 @@
package unix
-//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error)
//sys Dup2(oldfd int, newfd int) (err error)
+//sysnb EpollCreate(size int) (fd int, err error)
+//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error)
+//sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64
//sys Fchown(fd int, uid int, gid int) (err error)
//sys Fstat(fd int, stat *Stat_t) (err error)
+//sys Fstatat(dirfd int, path string, stat *Stat_t, flags int) (err error) = SYS_NEWFSTATAT
//sys Fstatfs(fd int, buf *Statfs_t) (err error)
//sys Ftruncate(fd int, length int64) (err error)
//sysnb Getegid() (egid int)
@@ -27,6 +30,7 @@ package unix
//sys Pause() (err error)
//sys Pread(fd int, p []byte, offset int64) (n int, err error) = SYS_PREAD64
//sys Pwrite(fd int, p []byte, offset int64) (n int, err error) = SYS_PWRITE64
+//sys Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error)
//sys Seek(fd int, offset int64, whence int) (off int64, err error) = SYS_LSEEK
//sys Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err error) = SYS__NEWSELECT
//sys sendfile(outfd int, infd int, offset *int64, count int) (written int, err error)
@@ -41,8 +45,8 @@ package unix
//sys Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, err error)
//sys Stat(path string, stat *Stat_t) (err error)
//sys Statfs(path string, buf *Statfs_t) (err error)
-//sys SyncFileRange(fd int, off int64, n int64, flags int) (err error) = SYS_SYNC_FILE_RANGE2
//sys Truncate(path string, length int64) (err error)
+//sys Ustat(dev int, ubuf *Ustat_t) (err error)
//sys accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error)
//sys accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int, err error)
//sys bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error)
@@ -61,24 +65,18 @@ package unix
//sys sendmsg(s int, msg *Msghdr, flags int) (n int, err error)
//sys mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, err error)
+//sys futimesat(dirfd int, path string, times *[2]Timeval) (err error)
//sysnb Gettimeofday(tv *Timeval) (err error)
//sysnb Time(t *Time_t) (tt Time_t, err error)
-
//sys Utime(path string, buf *Utimbuf) (err error)
+//sys utimes(path string, times *[2]Timeval) (err error)
-func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
-
-func NsecToTimespec(nsec int64) (ts Timespec) {
- ts.Sec = nsec / 1e9
- ts.Nsec = nsec % 1e9
- return
+func setTimespec(sec, nsec int64) Timespec {
+ return Timespec{Sec: sec, Nsec: nsec}
}
-func NsecToTimeval(nsec int64) (tv Timeval) {
- nsec += 999 // round up to microsecond
- tv.Sec = nsec / 1e9
- tv.Usec = nsec % 1e9 / 1e3
- return
+func setTimeval(sec, usec int64) Timeval {
+ return Timeval{Sec: sec, Usec: usec}
}
func (r *PtraceRegs) PC() uint64 { return r.Nip }
@@ -93,6 +91,10 @@ func (msghdr *Msghdr) SetControllen(length int) {
msghdr.Controllen = uint64(length)
}
+func (msghdr *Msghdr) SetIovlen(length int) {
+ msghdr.Iovlen = uint64(length)
+}
+
func (cmsg *Cmsghdr) SetLen(length int) {
cmsg.Len = uint64(length)
}
@@ -131,3 +133,24 @@ func Poll(fds []PollFd, timeout int) (n int, err error) {
}
return poll(&fds[0], len(fds), timeout)
}
+
+//sys syncFileRange2(fd int, flags int, off int64, n int64) (err error) = SYS_SYNC_FILE_RANGE2
+
+func SyncFileRange(fd int, off int64, n int64, flags int) error {
+ // The sync_file_range and sync_file_range2 syscalls differ only in the
+ // order of their arguments.
+ return syncFileRange2(fd, flags, off, n)
+}
+
+//sys kexecFileLoad(kernelFd int, initrdFd int, cmdlineLen int, cmdline string, flags int) (err error)
+
+func KexecFileLoad(kernelFd int, initrdFd int, cmdline string, flags int) error {
+ cmdlineLen := len(cmdline)
+ if cmdlineLen > 0 {
+ // Account for the additional NULL byte added by
+ // BytePtrFromString in kexecFileLoad. The kexec_file_load
+ // syscall expects a NULL-terminated string.
+ cmdlineLen++
+ }
+ return kexecFileLoad(kernelFd, initrdFd, cmdlineLen, cmdline, flags)
+}
diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_riscv64.go b/vendor/golang.org/x/sys/unix/syscall_linux_riscv64.go
new file mode 100644
index 0000000..6798c26
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/syscall_linux_riscv64.go
@@ -0,0 +1,230 @@
+// Copyright 2018 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 riscv64,linux
+
+package unix
+
+import "unsafe"
+
+func EpollCreate(size int) (fd int, err error) {
+ if size <= 0 {
+ return -1, EINVAL
+ }
+ return EpollCreate1(0)
+}
+
+//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) = SYS_EPOLL_PWAIT
+//sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64
+//sys Fchown(fd int, uid int, gid int) (err error)
+//sys Fstat(fd int, stat *Stat_t) (err error)
+//sys Fstatat(fd int, path string, stat *Stat_t, flags int) (err error)
+//sys Fstatfs(fd int, buf *Statfs_t) (err error)
+//sys Ftruncate(fd int, length int64) (err error)
+//sysnb Getegid() (egid int)
+//sysnb Geteuid() (euid int)
+//sysnb Getgid() (gid int)
+//sysnb Getrlimit(resource int, rlim *Rlimit) (err error)
+//sysnb Getuid() (uid int)
+//sys Listen(s int, n int) (err error)
+//sys Pread(fd int, p []byte, offset int64) (n int, err error) = SYS_PREAD64
+//sys Pwrite(fd int, p []byte, offset int64) (n int, err error) = SYS_PWRITE64
+//sys Seek(fd int, offset int64, whence int) (off int64, err error) = SYS_LSEEK
+
+func Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err error) {
+ var ts *Timespec
+ if timeout != nil {
+ ts = &Timespec{Sec: timeout.Sec, Nsec: timeout.Usec * 1000}
+ }
+ return Pselect(nfd, r, w, e, ts, nil)
+}
+
+//sys sendfile(outfd int, infd int, offset *int64, count int) (written int, err error)
+//sys Setfsgid(gid int) (err error)
+//sys Setfsuid(uid int) (err error)
+//sysnb Setregid(rgid int, egid int) (err error)
+//sysnb Setresgid(rgid int, egid int, sgid int) (err error)
+//sysnb Setresuid(ruid int, euid int, suid int) (err error)
+//sysnb Setrlimit(resource int, rlim *Rlimit) (err error)
+//sysnb Setreuid(ruid int, euid int) (err error)
+//sys Shutdown(fd int, how int) (err error)
+//sys Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, err error)
+
+func Stat(path string, stat *Stat_t) (err error) {
+ return Fstatat(AT_FDCWD, path, stat, 0)
+}
+
+func Lchown(path string, uid int, gid int) (err error) {
+ return Fchownat(AT_FDCWD, path, uid, gid, AT_SYMLINK_NOFOLLOW)
+}
+
+func Lstat(path string, stat *Stat_t) (err error) {
+ return Fstatat(AT_FDCWD, path, stat, AT_SYMLINK_NOFOLLOW)
+}
+
+//sys Statfs(path string, buf *Statfs_t) (err error)
+//sys SyncFileRange(fd int, off int64, n int64, flags int) (err error)
+//sys Truncate(path string, length int64) (err error)
+
+func Ustat(dev int, ubuf *Ustat_t) (err error) {
+ return ENOSYS
+}
+
+//sys accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error)
+//sys accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int, err error)
+//sys bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error)
+//sys connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error)
+//sysnb getgroups(n int, list *_Gid_t) (nn int, err error)
+//sysnb setgroups(n int, list *_Gid_t) (err error)
+//sys getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error)
+//sys setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error)
+//sysnb socket(domain int, typ int, proto int) (fd int, err error)
+//sysnb socketpair(domain int, typ int, proto int, fd *[2]int32) (err error)
+//sysnb getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error)
+//sysnb getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error)
+//sys recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error)
+//sys sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error)
+//sys recvmsg(s int, msg *Msghdr, flags int) (n int, err error)
+//sys sendmsg(s int, msg *Msghdr, flags int) (n int, err error)
+//sys mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, err error)
+
+//sysnb Gettimeofday(tv *Timeval) (err error)
+
+func setTimespec(sec, nsec int64) Timespec {
+ return Timespec{Sec: sec, Nsec: nsec}
+}
+
+func setTimeval(sec, usec int64) Timeval {
+ return Timeval{Sec: sec, Usec: usec}
+}
+
+func futimesat(dirfd int, path string, tv *[2]Timeval) (err error) {
+ if tv == nil {
+ return utimensat(dirfd, path, nil, 0)
+ }
+
+ ts := []Timespec{
+ NsecToTimespec(TimevalToNsec(tv[0])),
+ NsecToTimespec(TimevalToNsec(tv[1])),
+ }
+ return utimensat(dirfd, path, (*[2]Timespec)(unsafe.Pointer(&ts[0])), 0)
+}
+
+func Time(t *Time_t) (Time_t, error) {
+ var tv Timeval
+ err := Gettimeofday(&tv)
+ if err != nil {
+ return 0, err
+ }
+ if t != nil {
+ *t = Time_t(tv.Sec)
+ }
+ return Time_t(tv.Sec), nil
+}
+
+func Utime(path string, buf *Utimbuf) error {
+ tv := []Timeval{
+ {Sec: buf.Actime},
+ {Sec: buf.Modtime},
+ }
+ return Utimes(path, tv)
+}
+
+func utimes(path string, tv *[2]Timeval) (err error) {
+ if tv == nil {
+ return utimensat(AT_FDCWD, path, nil, 0)
+ }
+
+ ts := []Timespec{
+ NsecToTimespec(TimevalToNsec(tv[0])),
+ NsecToTimespec(TimevalToNsec(tv[1])),
+ }
+ return utimensat(AT_FDCWD, path, (*[2]Timespec)(unsafe.Pointer(&ts[0])), 0)
+}
+
+func Pipe(p []int) (err error) {
+ if len(p) != 2 {
+ return EINVAL
+ }
+ var pp [2]_C_int
+ err = pipe2(&pp, 0)
+ p[0] = int(pp[0])
+ p[1] = int(pp[1])
+ return
+}
+
+//sysnb pipe2(p *[2]_C_int, flags int) (err error)
+
+func Pipe2(p []int, flags int) (err error) {
+ if len(p) != 2 {
+ return EINVAL
+ }
+ var pp [2]_C_int
+ err = pipe2(&pp, flags)
+ p[0] = int(pp[0])
+ p[1] = int(pp[1])
+ return
+}
+
+func (r *PtraceRegs) PC() uint64 { return r.Pc }
+
+func (r *PtraceRegs) SetPC(pc uint64) { r.Pc = pc }
+
+func (iov *Iovec) SetLen(length int) {
+ iov.Len = uint64(length)
+}
+
+func (msghdr *Msghdr) SetControllen(length int) {
+ msghdr.Controllen = uint64(length)
+}
+
+func (msghdr *Msghdr) SetIovlen(length int) {
+ msghdr.Iovlen = uint64(length)
+}
+
+func (cmsg *Cmsghdr) SetLen(length int) {
+ cmsg.Len = uint64(length)
+}
+
+func InotifyInit() (fd int, err error) {
+ return InotifyInit1(0)
+}
+
+func Dup2(oldfd int, newfd int) (err error) {
+ return Dup3(oldfd, newfd, 0)
+}
+
+func Pause() error {
+ _, err := ppoll(nil, 0, nil, nil)
+ return err
+}
+
+func Poll(fds []PollFd, timeout int) (n int, err error) {
+ var ts *Timespec
+ if timeout >= 0 {
+ ts = new(Timespec)
+ *ts = NsecToTimespec(int64(timeout) * 1e6)
+ }
+ if len(fds) == 0 {
+ return ppoll(nil, 0, ts, nil)
+ }
+ return ppoll(&fds[0], len(fds), ts, nil)
+}
+
+func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) {
+ return Renameat2(olddirfd, oldpath, newdirfd, newpath, 0)
+}
+
+//sys kexecFileLoad(kernelFd int, initrdFd int, cmdlineLen int, cmdline string, flags int) (err error)
+
+func KexecFileLoad(kernelFd int, initrdFd int, cmdline string, flags int) error {
+ cmdlineLen := len(cmdline)
+ if cmdlineLen > 0 {
+ // Account for the additional NULL byte added by
+ // BytePtrFromString in kexecFileLoad. The kexec_file_load
+ // syscall expects a NULL-terminated string.
+ cmdlineLen++
+ }
+ return kexecFileLoad(kernelFd, initrdFd, cmdlineLen, cmdline, flags)
+}
diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_s390x.go b/vendor/golang.org/x/sys/unix/syscall_linux_s390x.go
index 3845fc9..eb5cb1a 100644
--- a/vendor/golang.org/x/sys/unix/syscall_linux_s390x.go
+++ b/vendor/golang.org/x/sys/unix/syscall_linux_s390x.go
@@ -11,10 +11,12 @@ import (
)
//sys Dup2(oldfd int, newfd int) (err error)
+//sysnb EpollCreate(size int) (fd int, err error)
//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error)
//sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64
//sys Fchown(fd int, uid int, gid int) (err error)
//sys Fstat(fd int, stat *Stat_t) (err error)
+//sys Fstatat(dirfd int, path string, stat *Stat_t, flags int) (err error) = SYS_NEWFSTATAT
//sys Fstatfs(fd int, buf *Statfs_t) (err error)
//sys Ftruncate(fd int, length int64) (err error)
//sysnb Getegid() (egid int)
@@ -28,6 +30,7 @@ import (
//sys Pause() (err error)
//sys Pread(fd int, p []byte, offset int64) (n int, err error) = SYS_PREAD64
//sys Pwrite(fd int, p []byte, offset int64) (n int, err error) = SYS_PWRITE64
+//sys Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error)
//sys Seek(fd int, offset int64, whence int) (off int64, err error) = SYS_LSEEK
//sys Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err error)
//sys sendfile(outfd int, infd int, offset *int64, count int) (written int, err error)
@@ -43,9 +46,11 @@ import (
//sys Statfs(path string, buf *Statfs_t) (err error)
//sys SyncFileRange(fd int, off int64, n int64, flags int) (err error)
//sys Truncate(path string, length int64) (err error)
+//sys Ustat(dev int, ubuf *Ustat_t) (err error)
//sysnb getgroups(n int, list *_Gid_t) (nn int, err error)
//sysnb setgroups(n int, list *_Gid_t) (err error)
+//sys futimesat(dirfd int, path string, times *[2]Timeval) (err error)
//sysnb Gettimeofday(tv *Timeval) (err error)
func Time(t *Time_t) (tt Time_t, err error) {
@@ -61,20 +66,14 @@ func Time(t *Time_t) (tt Time_t, err error) {
}
//sys Utime(path string, buf *Utimbuf) (err error)
+//sys utimes(path string, times *[2]Timeval) (err error)
-func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
-
-func NsecToTimespec(nsec int64) (ts Timespec) {
- ts.Sec = nsec / 1e9
- ts.Nsec = nsec % 1e9
- return
+func setTimespec(sec, nsec int64) Timespec {
+ return Timespec{Sec: sec, Nsec: nsec}
}
-func NsecToTimeval(nsec int64) (tv Timeval) {
- nsec += 999 // round up to microsecond
- tv.Sec = nsec / 1e9
- tv.Usec = nsec % 1e9 / 1e3
- return
+func setTimeval(sec, usec int64) Timeval {
+ return Timeval{Sec: sec, Usec: usec}
}
//sysnb pipe2(p *[2]_C_int, flags int) (err error)
@@ -121,6 +120,10 @@ func (msghdr *Msghdr) SetControllen(length int) {
msghdr.Controllen = uint64(length)
}
+func (msghdr *Msghdr) SetIovlen(length int) {
+ msghdr.Iovlen = uint64(length)
+}
+
func (cmsg *Cmsghdr) SetLen(length int) {
cmsg.Len = uint64(length)
}
@@ -324,3 +327,16 @@ func Poll(fds []PollFd, timeout int) (n int, err error) {
}
return poll(&fds[0], len(fds), timeout)
}
+
+//sys kexecFileLoad(kernelFd int, initrdFd int, cmdlineLen int, cmdline string, flags int) (err error)
+
+func KexecFileLoad(kernelFd int, initrdFd int, cmdline string, flags int) error {
+ cmdlineLen := len(cmdline)
+ if cmdlineLen > 0 {
+ // Account for the additional NULL byte added by
+ // BytePtrFromString in kexecFileLoad. The kexec_file_load
+ // syscall expects a NULL-terminated string.
+ cmdlineLen++
+ }
+ return kexecFileLoad(kernelFd, initrdFd, cmdlineLen, cmdline, flags)
+}
diff --git a/vendor/golang.org/x/sys/unix/syscall_linux_sparc64.go b/vendor/golang.org/x/sys/unix/syscall_linux_sparc64.go
index bd9de3e..37321c1 100644
--- a/vendor/golang.org/x/sys/unix/syscall_linux_sparc64.go
+++ b/vendor/golang.org/x/sys/unix/syscall_linux_sparc64.go
@@ -7,9 +7,11 @@
package unix
//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error)
+//sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64
//sys Dup2(oldfd int, newfd int) (err error)
//sys Fchown(fd int, uid int, gid int) (err error)
//sys Fstat(fd int, stat *Stat_t) (err error)
+//sys Fstatat(dirfd int, path string, stat *Stat_t, flags int) (err error) = SYS_FSTATAT64
//sys Fstatfs(fd int, buf *Statfs_t) (err error)
//sys Ftruncate(fd int, length int64) (err error)
//sysnb Getegid() (egid int)
@@ -24,6 +26,7 @@ package unix
//sys Pause() (err error)
//sys Pread(fd int, p []byte, offset int64) (n int, err error) = SYS_PREAD64
//sys Pwrite(fd int, p []byte, offset int64) (n int, err error) = SYS_PWRITE64
+//sys Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error)
//sys Seek(fd int, offset int64, whence int) (off int64, err error) = SYS_LSEEK
//sys Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err error)
//sys sendfile(outfd int, infd int, offset *int64, count int) (written int, err error)
@@ -66,6 +69,7 @@ func Iopl(level int) (err error) {
return ENOSYS
}
+//sys futimesat(dirfd int, path string, times *[2]Timeval) (err error)
//sysnb Gettimeofday(tv *Timeval) (err error)
func Time(t *Time_t) (tt Time_t, err error) {
@@ -81,20 +85,14 @@ func Time(t *Time_t) (tt Time_t, err error) {
}
//sys Utime(path string, buf *Utimbuf) (err error)
+//sys utimes(path string, times *[2]Timeval) (err error)
-func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
-
-func NsecToTimespec(nsec int64) (ts Timespec) {
- ts.Sec = nsec / 1e9
- ts.Nsec = nsec % 1e9
- return
+func setTimespec(sec, nsec int64) Timespec {
+ return Timespec{Sec: sec, Nsec: nsec}
}
-func NsecToTimeval(nsec int64) (tv Timeval) {
- nsec += 999 // round up to microsecond
- tv.Sec = nsec / 1e9
- tv.Usec = int32(nsec % 1e9 / 1e3)
- return
+func setTimeval(sec, usec int64) Timeval {
+ return Timeval{Sec: sec, Usec: int32(usec)}
}
func (r *PtraceRegs) PC() uint64 { return r.Tpc }
@@ -109,6 +107,10 @@ func (msghdr *Msghdr) SetControllen(length int) {
msghdr.Controllen = uint64(length)
}
+func (msghdr *Msghdr) SetIovlen(length int) {
+ msghdr.Iovlen = uint64(length)
+}
+
func (cmsg *Cmsghdr) SetLen(length int) {
cmsg.Len = uint64(length)
}
diff --git a/vendor/golang.org/x/sys/unix/syscall_netbsd.go b/vendor/golang.org/x/sys/unix/syscall_netbsd.go
index e129668..6135d38 100644
--- a/vendor/golang.org/x/sys/unix/syscall_netbsd.go
+++ b/vendor/golang.org/x/sys/unix/syscall_netbsd.go
@@ -13,10 +13,12 @@
package unix
import (
+ "runtime"
"syscall"
"unsafe"
)
+// SockaddrDatalink implements the Sockaddr interface for AF_LINK type sockets.
type SockaddrDatalink struct {
Len uint8
Family uint8
@@ -55,7 +57,6 @@ func sysctlNodes(mib []_C_int) (nodes []Sysctlnode, err error) {
}
func nametomib(name string) (mib []_C_int, err error) {
-
// Split name into components.
var parts []string
last := 0
@@ -105,6 +106,23 @@ func direntNamlen(buf []byte) (uint64, bool) {
return readInt(buf, unsafe.Offsetof(Dirent{}.Namlen), unsafe.Sizeof(Dirent{}.Namlen))
}
+func SysctlClockinfo(name string) (*Clockinfo, error) {
+ mib, err := sysctlmib(name)
+ if err != nil {
+ return nil, err
+ }
+
+ n := uintptr(SizeofClockinfo)
+ var ci Clockinfo
+ if err := sysctl(mib, (*byte)(unsafe.Pointer(&ci)), &n, nil, 0); err != nil {
+ return nil, err
+ }
+ if n != SizeofClockinfo {
+ return nil, EIO
+ }
+ return &ci, nil
+}
+
//sysnb pipe() (fd1 int, fd2 int, err error)
func Pipe(p []int) (err error) {
if len(p) != 2 {
@@ -114,9 +132,47 @@ func Pipe(p []int) (err error) {
return
}
-//sys getdents(fd int, buf []byte) (n int, err error)
+//sys Getdents(fd int, buf []byte) (n int, err error)
func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
- return getdents(fd, buf)
+ n, err = Getdents(fd, buf)
+ if err != nil || basep == nil {
+ return
+ }
+
+ var off int64
+ off, err = Seek(fd, 0, 1 /* SEEK_CUR */)
+ if err != nil {
+ *basep = ^uintptr(0)
+ return
+ }
+ *basep = uintptr(off)
+ if unsafe.Sizeof(*basep) == 8 {
+ return
+ }
+ if off>>32 != 0 {
+ // We can't stuff the offset back into a uintptr, so any
+ // future calls would be suspect. Generate an error.
+ // EIO is allowed by getdirentries.
+ err = EIO
+ }
+ return
+}
+
+const ImplementsGetwd = true
+
+//sys Getcwd(buf []byte) (n int, err error) = SYS___GETCWD
+
+func Getwd() (string, error) {
+ var buf [PathMax]byte
+ _, err := Getcwd(buf[0:])
+ if err != nil {
+ return "", err
+ }
+ n := clen(buf[:])
+ if n < 1 {
+ return "", EINVAL
+ }
+ return string(buf[:n]), nil
}
// TODO
@@ -124,6 +180,83 @@ func sendfile(outfd int, infd int, offset *int64, count int) (written int, err e
return -1, ENOSYS
}
+func setattrlistTimes(path string, times []Timespec, flags int) error {
+ // used on Darwin for UtimesNano
+ return ENOSYS
+}
+
+//sys ioctl(fd int, req uint, arg uintptr) (err error)
+
+//sys sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) = SYS___SYSCTL
+
+func IoctlGetPtmget(fd int, req uint) (*Ptmget, error) {
+ var value Ptmget
+ err := ioctl(fd, req, uintptr(unsafe.Pointer(&value)))
+ runtime.KeepAlive(value)
+ return &value, err
+}
+
+func Uname(uname *Utsname) error {
+ mib := []_C_int{CTL_KERN, KERN_OSTYPE}
+ n := unsafe.Sizeof(uname.Sysname)
+ if err := sysctl(mib, &uname.Sysname[0], &n, nil, 0); err != nil {
+ return err
+ }
+
+ mib = []_C_int{CTL_KERN, KERN_HOSTNAME}
+ n = unsafe.Sizeof(uname.Nodename)
+ if err := sysctl(mib, &uname.Nodename[0], &n, nil, 0); err != nil {
+ return err
+ }
+
+ mib = []_C_int{CTL_KERN, KERN_OSRELEASE}
+ n = unsafe.Sizeof(uname.Release)
+ if err := sysctl(mib, &uname.Release[0], &n, nil, 0); err != nil {
+ return err
+ }
+
+ mib = []_C_int{CTL_KERN, KERN_VERSION}
+ n = unsafe.Sizeof(uname.Version)
+ if err := sysctl(mib, &uname.Version[0], &n, nil, 0); err != nil {
+ return err
+ }
+
+ // The version might have newlines or tabs in it, convert them to
+ // spaces.
+ for i, b := range uname.Version {
+ if b == '\n' || b == '\t' {
+ if i == len(uname.Version)-1 {
+ uname.Version[i] = 0
+ } else {
+ uname.Version[i] = ' '
+ }
+ }
+ }
+
+ mib = []_C_int{CTL_HW, HW_MACHINE}
+ n = unsafe.Sizeof(uname.Machine)
+ if err := sysctl(mib, &uname.Machine[0], &n, nil, 0); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
+ if raceenabled {
+ raceReleaseMerge(unsafe.Pointer(&ioSync))
+ }
+ return sendfile(outfd, infd, offset, count)
+}
+
+func Fstatvfs(fd int, buf *Statvfs_t) (err error) {
+ return Fstatvfs1(fd, buf, ST_WAIT)
+}
+
+func Statvfs(path string, buf *Statvfs_t) (err error) {
+ return Statvfs1(path, buf, ST_WAIT)
+}
+
/*
* Exposed directly
*/
@@ -138,13 +271,31 @@ func sendfile(outfd int, infd int, offset *int64, count int) (written int, err e
//sys Dup(fd int) (nfd int, err error)
//sys Dup2(from int, to int) (err error)
//sys Exit(code int)
+//sys ExtattrGetFd(fd int, attrnamespace int, attrname string, data uintptr, nbytes int) (ret int, err error)
+//sys ExtattrSetFd(fd int, attrnamespace int, attrname string, data uintptr, nbytes int) (ret int, err error)
+//sys ExtattrDeleteFd(fd int, attrnamespace int, attrname string) (err error)
+//sys ExtattrListFd(fd int, attrnamespace int, data uintptr, nbytes int) (ret int, err error)
+//sys ExtattrGetFile(file string, attrnamespace int, attrname string, data uintptr, nbytes int) (ret int, err error)
+//sys ExtattrSetFile(file string, attrnamespace int, attrname string, data uintptr, nbytes int) (ret int, err error)
+//sys ExtattrDeleteFile(file string, attrnamespace int, attrname string) (err error)
+//sys ExtattrListFile(file string, attrnamespace int, data uintptr, nbytes int) (ret int, err error)
+//sys ExtattrGetLink(link string, attrnamespace int, attrname string, data uintptr, nbytes int) (ret int, err error)
+//sys ExtattrSetLink(link string, attrnamespace int, attrname string, data uintptr, nbytes int) (ret int, err error)
+//sys ExtattrDeleteLink(link string, attrnamespace int, attrname string) (err error)
+//sys ExtattrListLink(link string, attrnamespace int, data uintptr, nbytes int) (ret int, err error)
+//sys Faccessat(dirfd int, path string, mode uint32, flags int) (err error)
+//sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_POSIX_FADVISE
//sys Fchdir(fd int) (err error)
//sys Fchflags(fd int, flags int) (err error)
//sys Fchmod(fd int, mode uint32) (err error)
+//sys Fchmodat(dirfd int, path string, mode uint32, flags int) (err error)
//sys Fchown(fd int, uid int, gid int) (err error)
+//sys Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error)
//sys Flock(fd int, how int) (err error)
//sys Fpathconf(fd int, name int) (val int, err error)
//sys Fstat(fd int, stat *Stat_t) (err error)
+//sys Fstatat(fd int, path string, stat *Stat_t, flags int) (err error)
+//sys Fstatvfs1(fd int, buf *Statvfs_t) (err error) = SYS_FSTATVFS1
//sys Fsync(fd int) (err error)
//sys Ftruncate(fd int, length int64) (err error)
//sysnb Getegid() (egid int)
@@ -165,23 +316,30 @@ func sendfile(outfd int, infd int, offset *int64, count int) (written int, err e
//sys Kqueue() (fd int, err error)
//sys Lchown(path string, uid int, gid int) (err error)
//sys Link(path string, link string) (err error)
+//sys Linkat(pathfd int, path string, linkfd int, link string, flags int) (err error)
//sys Listen(s int, backlog int) (err error)
//sys Lstat(path string, stat *Stat_t) (err error)
//sys Mkdir(path string, mode uint32) (err error)
+//sys Mkdirat(dirfd int, path string, mode uint32) (err error)
//sys Mkfifo(path string, mode uint32) (err error)
+//sys Mkfifoat(dirfd int, path string, mode uint32) (err error)
//sys Mknod(path string, mode uint32, dev int) (err error)
+//sys Mknodat(dirfd int, path string, mode uint32, dev int) (err error)
//sys Nanosleep(time *Timespec, leftover *Timespec) (err error)
//sys Open(path string, mode int, perm uint32) (fd int, err error)
+//sys Openat(dirfd int, path string, mode int, perm uint32) (fd int, err error)
//sys Pathconf(path string, name int) (val int, err error)
//sys Pread(fd int, p []byte, offset int64) (n int, err error)
//sys Pwrite(fd int, p []byte, offset int64) (n int, err error)
//sys read(fd int, p []byte) (n int, err error)
//sys Readlink(path string, buf []byte) (n int, err error)
+//sys Readlinkat(dirfd int, path string, buf []byte) (n int, err error)
//sys Rename(from string, to string) (err error)
+//sys Renameat(fromfd int, from string, tofd int, to string) (err error)
//sys Revoke(path string) (err error)
//sys Rmdir(path string) (err error)
//sys Seek(fd int, offset int64, whence int) (newoffset int64, err error) = SYS_LSEEK
-//sys Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error)
+//sys Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err error)
//sysnb Setegid(egid int) (err error)
//sysnb Seteuid(euid int) (err error)
//sysnb Setgid(gid int) (err error)
@@ -194,11 +352,14 @@ func sendfile(outfd int, infd int, offset *int64, count int) (written int, err e
//sysnb Settimeofday(tp *Timeval) (err error)
//sysnb Setuid(uid int) (err error)
//sys Stat(path string, stat *Stat_t) (err error)
+//sys Statvfs1(path string, buf *Statvfs_t) (err error) = SYS_STATVFS1
//sys Symlink(path string, link string) (err error)
+//sys Symlinkat(oldpath string, newdirfd int, newpath string) (err error)
//sys Sync() (err error)
//sys Truncate(path string, length int64) (err error)
//sys Umask(newmask int) (oldmask int)
//sys Unlink(path string) (err error)
+//sys Unlinkat(dirfd int, path string, flags int) (err error)
//sys Unmount(path string, flags int) (err error)
//sys write(fd int, p []byte) (n int, err error)
//sys mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error)
@@ -225,7 +386,6 @@ func sendfile(outfd int, infd int, offset *int64, count int) (written int, err e
// __msync13
// __ntp_gettime30
// __posix_chown
-// __posix_fadvise50
// __posix_fchown
// __posix_lchown
// __posix_rename
@@ -384,7 +544,6 @@ func sendfile(outfd int, infd int, offset *int64, count int) (written int, err e
// getitimer
// getvfsstat
// getxattr
-// ioctl
// ktrace
// lchflags
// lchmod
@@ -422,7 +581,6 @@ func sendfile(outfd int, infd int, offset *int64, count int) (written int, err e
// ntp_adjtime
// pmc_control
// pmc_get_info
-// poll
// pollts
// preadv
// profil
diff --git a/vendor/golang.org/x/sys/unix/syscall_netbsd_386.go b/vendor/golang.org/x/sys/unix/syscall_netbsd_386.go
index baefa41..24da8b5 100644
--- a/vendor/golang.org/x/sys/unix/syscall_netbsd_386.go
+++ b/vendor/golang.org/x/sys/unix/syscall_netbsd_386.go
@@ -6,19 +6,12 @@
package unix
-func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
-
-func NsecToTimespec(nsec int64) (ts Timespec) {
- ts.Sec = int64(nsec / 1e9)
- ts.Nsec = int32(nsec % 1e9)
- return
+func setTimespec(sec, nsec int64) Timespec {
+ return Timespec{Sec: sec, Nsec: int32(nsec)}
}
-func NsecToTimeval(nsec int64) (tv Timeval) {
- nsec += 999 // round up to microsecond
- tv.Usec = int32(nsec % 1e9 / 1e3)
- tv.Sec = int64(nsec / 1e9)
- return
+func setTimeval(sec, usec int64) Timeval {
+ return Timeval{Sec: sec, Usec: int32(usec)}
}
func SetKevent(k *Kevent_t, fd, mode, flags int) {
@@ -35,6 +28,10 @@ func (msghdr *Msghdr) SetControllen(length int) {
msghdr.Controllen = uint32(length)
}
+func (msghdr *Msghdr) SetIovlen(length int) {
+ msghdr.Iovlen = int32(length)
+}
+
func (cmsg *Cmsghdr) SetLen(length int) {
cmsg.Len = uint32(length)
}
diff --git a/vendor/golang.org/x/sys/unix/syscall_netbsd_amd64.go b/vendor/golang.org/x/sys/unix/syscall_netbsd_amd64.go
index 59c2ab7..25a0ac8 100644
--- a/vendor/golang.org/x/sys/unix/syscall_netbsd_amd64.go
+++ b/vendor/golang.org/x/sys/unix/syscall_netbsd_amd64.go
@@ -6,19 +6,12 @@
package unix
-func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
-
-func NsecToTimespec(nsec int64) (ts Timespec) {
- ts.Sec = int64(nsec / 1e9)
- ts.Nsec = int64(nsec % 1e9)
- return
+func setTimespec(sec, nsec int64) Timespec {
+ return Timespec{Sec: sec, Nsec: nsec}
}
-func NsecToTimeval(nsec int64) (tv Timeval) {
- nsec += 999 // round up to microsecond
- tv.Usec = int32(nsec % 1e9 / 1e3)
- tv.Sec = int64(nsec / 1e9)
- return
+func setTimeval(sec, usec int64) Timeval {
+ return Timeval{Sec: sec, Usec: int32(usec)}
}
func SetKevent(k *Kevent_t, fd, mode, flags int) {
@@ -35,6 +28,10 @@ func (msghdr *Msghdr) SetControllen(length int) {
msghdr.Controllen = uint32(length)
}
+func (msghdr *Msghdr) SetIovlen(length int) {
+ msghdr.Iovlen = int32(length)
+}
+
func (cmsg *Cmsghdr) SetLen(length int) {
cmsg.Len = uint32(length)
}
diff --git a/vendor/golang.org/x/sys/unix/syscall_netbsd_arm.go b/vendor/golang.org/x/sys/unix/syscall_netbsd_arm.go
index 7208108..21591ec 100644
--- a/vendor/golang.org/x/sys/unix/syscall_netbsd_arm.go
+++ b/vendor/golang.org/x/sys/unix/syscall_netbsd_arm.go
@@ -6,19 +6,12 @@
package unix
-func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
-
-func NsecToTimespec(nsec int64) (ts Timespec) {
- ts.Sec = int64(nsec / 1e9)
- ts.Nsec = int32(nsec % 1e9)
- return
+func setTimespec(sec, nsec int64) Timespec {
+ return Timespec{Sec: sec, Nsec: int32(nsec)}
}
-func NsecToTimeval(nsec int64) (tv Timeval) {
- nsec += 999 // round up to microsecond
- tv.Usec = int32(nsec % 1e9 / 1e3)
- tv.Sec = int64(nsec / 1e9)
- return
+func setTimeval(sec, usec int64) Timeval {
+ return Timeval{Sec: sec, Usec: int32(usec)}
}
func SetKevent(k *Kevent_t, fd, mode, flags int) {
@@ -35,6 +28,10 @@ func (msghdr *Msghdr) SetControllen(length int) {
msghdr.Controllen = uint32(length)
}
+func (msghdr *Msghdr) SetIovlen(length int) {
+ msghdr.Iovlen = int32(length)
+}
+
func (cmsg *Cmsghdr) SetLen(length int) {
cmsg.Len = uint32(length)
}
diff --git a/vendor/golang.org/x/sys/unix/syscall_netbsd_arm64.go b/vendor/golang.org/x/sys/unix/syscall_netbsd_arm64.go
new file mode 100644
index 0000000..8047496
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/syscall_netbsd_arm64.go
@@ -0,0 +1,37 @@
+// Copyright 2019 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 arm64,netbsd
+
+package unix
+
+func setTimespec(sec, nsec int64) Timespec {
+ return Timespec{Sec: sec, Nsec: nsec}
+}
+
+func setTimeval(sec, usec int64) Timeval {
+ return Timeval{Sec: sec, Usec: int32(usec)}
+}
+
+func SetKevent(k *Kevent_t, fd, mode, flags int) {
+ k.Ident = uint64(fd)
+ k.Filter = uint32(mode)
+ k.Flags = uint32(flags)
+}
+
+func (iov *Iovec) SetLen(length int) {
+ iov.Len = uint64(length)
+}
+
+func (msghdr *Msghdr) SetControllen(length int) {
+ msghdr.Controllen = uint32(length)
+}
+
+func (msghdr *Msghdr) SetIovlen(length int) {
+ msghdr.Iovlen = int32(length)
+}
+
+func (cmsg *Cmsghdr) SetLen(length int) {
+ cmsg.Len = uint32(length)
+}
diff --git a/vendor/golang.org/x/sys/unix/syscall_no_getwd.go b/vendor/golang.org/x/sys/unix/syscall_no_getwd.go
deleted file mode 100644
index 530792e..0000000
--- a/vendor/golang.org/x/sys/unix/syscall_no_getwd.go
+++ /dev/null
@@ -1,11 +0,0 @@
-// Copyright 2013 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 dragonfly freebsd netbsd openbsd
-
-package unix
-
-const ImplementsGetwd = false
-
-func Getwd() (string, error) { return "", ENOTSUP }
diff --git a/vendor/golang.org/x/sys/unix/syscall_openbsd.go b/vendor/golang.org/x/sys/unix/syscall_openbsd.go
index 408e630..5ca0df2 100644
--- a/vendor/golang.org/x/sys/unix/syscall_openbsd.go
+++ b/vendor/golang.org/x/sys/unix/syscall_openbsd.go
@@ -13,10 +13,12 @@
package unix
import (
+ "sort"
"syscall"
"unsafe"
)
+// SockaddrDatalink implements the Sockaddr interface for AF_LINK type sockets.
type SockaddrDatalink struct {
Len uint8
Family uint8
@@ -32,23 +34,11 @@ type SockaddrDatalink struct {
func Syscall9(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno)
func nametomib(name string) (mib []_C_int, err error) {
-
- // Perform lookup via a binary search
- left := 0
- right := len(sysctlMib) - 1
- for {
- idx := left + (right-left)/2
- switch {
- case name == sysctlMib[idx].ctlname:
- return sysctlMib[idx].ctloid, nil
- case name > sysctlMib[idx].ctlname:
- left = idx + 1
- default:
- right = idx - 1
- }
- if left > right {
- break
- }
+ i := sort.Search(len(sysctlMib), func(i int) bool {
+ return sysctlMib[i].ctlname >= name
+ })
+ if i < len(sysctlMib) && sysctlMib[i].ctlname == name {
+ return sysctlMib[i].ctloid, nil
}
return nil, EINVAL
}
@@ -65,6 +55,40 @@ func direntNamlen(buf []byte) (uint64, bool) {
return readInt(buf, unsafe.Offsetof(Dirent{}.Namlen), unsafe.Sizeof(Dirent{}.Namlen))
}
+func SysctlClockinfo(name string) (*Clockinfo, error) {
+ mib, err := sysctlmib(name)
+ if err != nil {
+ return nil, err
+ }
+
+ n := uintptr(SizeofClockinfo)
+ var ci Clockinfo
+ if err := sysctl(mib, (*byte)(unsafe.Pointer(&ci)), &n, nil, 0); err != nil {
+ return nil, err
+ }
+ if n != SizeofClockinfo {
+ return nil, EIO
+ }
+ return &ci, nil
+}
+
+func SysctlUvmexp(name string) (*Uvmexp, error) {
+ mib, err := sysctlmib(name)
+ if err != nil {
+ return nil, err
+ }
+
+ n := uintptr(SizeofUvmexp)
+ var u Uvmexp
+ if err := sysctl(mib, (*byte)(unsafe.Pointer(&u)), &n, nil, 0); err != nil {
+ return nil, err
+ }
+ if n != SizeofUvmexp {
+ return nil, EIO
+ }
+ return &u, nil
+}
+
//sysnb pipe(p *[2]_C_int) (err error)
func Pipe(p []int) (err error) {
if len(p) != 2 {
@@ -77,9 +101,54 @@ func Pipe(p []int) (err error) {
return
}
-//sys getdents(fd int, buf []byte) (n int, err error)
+//sys Getdents(fd int, buf []byte) (n int, err error)
func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
- return getdents(fd, buf)
+ n, err = Getdents(fd, buf)
+ if err != nil || basep == nil {
+ return
+ }
+
+ var off int64
+ off, err = Seek(fd, 0, 1 /* SEEK_CUR */)
+ if err != nil {
+ *basep = ^uintptr(0)
+ return
+ }
+ *basep = uintptr(off)
+ if unsafe.Sizeof(*basep) == 8 {
+ return
+ }
+ if off>>32 != 0 {
+ // We can't stuff the offset back into a uintptr, so any
+ // future calls would be suspect. Generate an error.
+ // EIO was allowed by getdirentries.
+ err = EIO
+ }
+ return
+}
+
+const ImplementsGetwd = true
+
+//sys Getcwd(buf []byte) (n int, err error) = SYS___GETCWD
+
+func Getwd() (string, error) {
+ var buf [PathMax]byte
+ _, err := Getcwd(buf[0:])
+ if err != nil {
+ return "", err
+ }
+ n := clen(buf[:])
+ if n < 1 {
+ return "", EINVAL
+ }
+ return string(buf[:n]), nil
+}
+
+func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
+ if raceenabled {
+ raceReleaseMerge(unsafe.Pointer(&ioSync))
+ }
+ return sendfile(outfd, infd, offset, count)
}
// TODO
@@ -102,6 +171,70 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
return
}
+func setattrlistTimes(path string, times []Timespec, flags int) error {
+ // used on Darwin for UtimesNano
+ return ENOSYS
+}
+
+//sys ioctl(fd int, req uint, arg uintptr) (err error)
+
+//sys sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) = SYS___SYSCTL
+
+//sys ppoll(fds *PollFd, nfds int, timeout *Timespec, sigmask *Sigset_t) (n int, err error)
+
+func Ppoll(fds []PollFd, timeout *Timespec, sigmask *Sigset_t) (n int, err error) {
+ if len(fds) == 0 {
+ return ppoll(nil, 0, timeout, sigmask)
+ }
+ return ppoll(&fds[0], len(fds), timeout, sigmask)
+}
+
+func Uname(uname *Utsname) error {
+ mib := []_C_int{CTL_KERN, KERN_OSTYPE}
+ n := unsafe.Sizeof(uname.Sysname)
+ if err := sysctl(mib, &uname.Sysname[0], &n, nil, 0); err != nil {
+ return err
+ }
+
+ mib = []_C_int{CTL_KERN, KERN_HOSTNAME}
+ n = unsafe.Sizeof(uname.Nodename)
+ if err := sysctl(mib, &uname.Nodename[0], &n, nil, 0); err != nil {
+ return err
+ }
+
+ mib = []_C_int{CTL_KERN, KERN_OSRELEASE}
+ n = unsafe.Sizeof(uname.Release)
+ if err := sysctl(mib, &uname.Release[0], &n, nil, 0); err != nil {
+ return err
+ }
+
+ mib = []_C_int{CTL_KERN, KERN_VERSION}
+ n = unsafe.Sizeof(uname.Version)
+ if err := sysctl(mib, &uname.Version[0], &n, nil, 0); err != nil {
+ return err
+ }
+
+ // The version might have newlines or tabs in it, convert them to
+ // spaces.
+ for i, b := range uname.Version {
+ if b == '\n' || b == '\t' {
+ if i == len(uname.Version)-1 {
+ uname.Version[i] = 0
+ } else {
+ uname.Version[i] = ' '
+ }
+ }
+ }
+
+ mib = []_C_int{CTL_HW, HW_MACHINE}
+ n = unsafe.Sizeof(uname.Machine)
+ if err := sysctl(mib, &uname.Machine[0], &n, nil, 0); err != nil {
+ return err
+ }
+
+ return nil
+}
+
/*
* Exposed directly
*/
@@ -116,13 +249,17 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
//sys Dup(fd int) (nfd int, err error)
//sys Dup2(from int, to int) (err error)
//sys Exit(code int)
+//sys Faccessat(dirfd int, path string, mode uint32, flags int) (err error)
//sys Fchdir(fd int) (err error)
//sys Fchflags(fd int, flags int) (err error)
//sys Fchmod(fd int, mode uint32) (err error)
+//sys Fchmodat(dirfd int, path string, mode uint32, flags int) (err error)
//sys Fchown(fd int, uid int, gid int) (err error)
+//sys Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error)
//sys Flock(fd int, how int) (err error)
//sys Fpathconf(fd int, name int) (val int, err error)
//sys Fstat(fd int, stat *Stat_t) (err error)
+//sys Fstatat(fd int, path string, stat *Stat_t, flags int) (err error)
//sys Fstatfs(fd int, stat *Statfs_t) (err error)
//sys Fsync(fd int) (err error)
//sys Ftruncate(fd int, length int64) (err error)
@@ -135,6 +272,7 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
//sysnb Getppid() (ppid int)
//sys Getpriority(which int, who int) (prio int, err error)
//sysnb Getrlimit(which int, lim *Rlimit) (err error)
+//sysnb Getrtable() (rtable int, err error)
//sysnb Getrusage(who int, rusage *Rusage) (err error)
//sysnb Getsid(pid int) (sid int, err error)
//sysnb Gettimeofday(tv *Timeval) (err error)
@@ -144,23 +282,30 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
//sys Kqueue() (fd int, err error)
//sys Lchown(path string, uid int, gid int) (err error)
//sys Link(path string, link string) (err error)
+//sys Linkat(pathfd int, path string, linkfd int, link string, flags int) (err error)
//sys Listen(s int, backlog int) (err error)
//sys Lstat(path string, stat *Stat_t) (err error)
//sys Mkdir(path string, mode uint32) (err error)
+//sys Mkdirat(dirfd int, path string, mode uint32) (err error)
//sys Mkfifo(path string, mode uint32) (err error)
+//sys Mkfifoat(dirfd int, path string, mode uint32) (err error)
//sys Mknod(path string, mode uint32, dev int) (err error)
+//sys Mknodat(dirfd int, path string, mode uint32, dev int) (err error)
//sys Nanosleep(time *Timespec, leftover *Timespec) (err error)
//sys Open(path string, mode int, perm uint32) (fd int, err error)
+//sys Openat(dirfd int, path string, mode int, perm uint32) (fd int, err error)
//sys Pathconf(path string, name int) (val int, err error)
//sys Pread(fd int, p []byte, offset int64) (n int, err error)
//sys Pwrite(fd int, p []byte, offset int64) (n int, err error)
//sys read(fd int, p []byte) (n int, err error)
//sys Readlink(path string, buf []byte) (n int, err error)
+//sys Readlinkat(dirfd int, path string, buf []byte) (n int, err error)
//sys Rename(from string, to string) (err error)
+//sys Renameat(fromfd int, from string, tofd int, to string) (err error)
//sys Revoke(path string) (err error)
//sys Rmdir(path string) (err error)
//sys Seek(fd int, offset int64, whence int) (newoffset int64, err error) = SYS_LSEEK
-//sys Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error)
+//sys Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err error)
//sysnb Setegid(egid int) (err error)
//sysnb Seteuid(euid int) (err error)
//sysnb Setgid(gid int) (err error)
@@ -172,16 +317,19 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
//sysnb Setresgid(rgid int, egid int, sgid int) (err error)
//sysnb Setresuid(ruid int, euid int, suid int) (err error)
//sysnb Setrlimit(which int, lim *Rlimit) (err error)
+//sysnb Setrtable(rtable int) (err error)
//sysnb Setsid() (pid int, err error)
//sysnb Settimeofday(tp *Timeval) (err error)
//sysnb Setuid(uid int) (err error)
//sys Stat(path string, stat *Stat_t) (err error)
//sys Statfs(path string, stat *Statfs_t) (err error)
//sys Symlink(path string, link string) (err error)
+//sys Symlinkat(oldpath string, newdirfd int, newpath string) (err error)
//sys Sync() (err error)
//sys Truncate(path string, length int64) (err error)
//sys Umask(newmask int) (oldmask int)
//sys Unlink(path string) (err error)
+//sys Unlinkat(dirfd int, path string, flags int) (err error)
//sys Unmount(path string, flags int) (err error)
//sys write(fd int, p []byte) (n int, err error)
//sys mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error)
@@ -204,15 +352,10 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
// clock_settime
// closefrom
// execve
-// faccessat
-// fchmodat
-// fchownat
-// fcntl
// fhopen
// fhstat
// fhstatfs
// fork
-// fstatat
// futimens
// getfh
// getgid
@@ -220,20 +363,14 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
// getlogin
// getresgid
// getresuid
-// getrtable
// getthrid
-// ioctl
// ktrace
// lfs_bmapv
// lfs_markv
// lfs_segclean
// lfs_segwait
-// linkat
// mincore
// minherit
-// mkdirat
-// mkfifoat
-// mknodat
// mount
// mquery
// msgctl
@@ -242,13 +379,10 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
// msgsnd
// nfssvc
// nnpfspioctl
-// openat
-// poll
// preadv
// profil
// pwritev
// quotactl
-// readlinkat
// readv
// reboot
// renameat
@@ -258,7 +392,6 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
// semop
// setgroups
// setitimer
-// setrtable
// setsockopt
// shmat
// shmctl
@@ -270,13 +403,11 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
// sigprocmask
// sigreturn
// sigsuspend
-// symlinkat
// sysarch
// syscall
// threxit
// thrsigdivert
// thrsleep
// thrwakeup
-// unlinkat
// vfork
// writev
diff --git a/vendor/golang.org/x/sys/unix/syscall_openbsd_386.go b/vendor/golang.org/x/sys/unix/syscall_openbsd_386.go
index d3809b4..42b5a0e 100644
--- a/vendor/golang.org/x/sys/unix/syscall_openbsd_386.go
+++ b/vendor/golang.org/x/sys/unix/syscall_openbsd_386.go
@@ -6,19 +6,12 @@
package unix
-func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
-
-func NsecToTimespec(nsec int64) (ts Timespec) {
- ts.Sec = int64(nsec / 1e9)
- ts.Nsec = int32(nsec % 1e9)
- return
+func setTimespec(sec, nsec int64) Timespec {
+ return Timespec{Sec: sec, Nsec: int32(nsec)}
}
-func NsecToTimeval(nsec int64) (tv Timeval) {
- nsec += 999 // round up to microsecond
- tv.Usec = int32(nsec % 1e9 / 1e3)
- tv.Sec = int64(nsec / 1e9)
- return
+func setTimeval(sec, usec int64) Timeval {
+ return Timeval{Sec: sec, Usec: int32(usec)}
}
func SetKevent(k *Kevent_t, fd, mode, flags int) {
@@ -35,6 +28,14 @@ func (msghdr *Msghdr) SetControllen(length int) {
msghdr.Controllen = uint32(length)
}
+func (msghdr *Msghdr) SetIovlen(length int) {
+ msghdr.Iovlen = uint32(length)
+}
+
func (cmsg *Cmsghdr) SetLen(length int) {
cmsg.Len = uint32(length)
}
+
+// SYS___SYSCTL is used by syscall_bsd.go for all BSDs, but in modern versions
+// of openbsd/386 the syscall is called sysctl instead of __sysctl.
+const SYS___SYSCTL = SYS_SYSCTL
diff --git a/vendor/golang.org/x/sys/unix/syscall_openbsd_amd64.go b/vendor/golang.org/x/sys/unix/syscall_openbsd_amd64.go
index 9a9dfce..6ea4b48 100644
--- a/vendor/golang.org/x/sys/unix/syscall_openbsd_amd64.go
+++ b/vendor/golang.org/x/sys/unix/syscall_openbsd_amd64.go
@@ -6,19 +6,12 @@
package unix
-func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
-
-func NsecToTimespec(nsec int64) (ts Timespec) {
- ts.Sec = nsec / 1e9
- ts.Nsec = nsec % 1e9
- return
+func setTimespec(sec, nsec int64) Timespec {
+ return Timespec{Sec: sec, Nsec: nsec}
}
-func NsecToTimeval(nsec int64) (tv Timeval) {
- nsec += 999 // round up to microsecond
- tv.Usec = nsec % 1e9 / 1e3
- tv.Sec = nsec / 1e9
- return
+func setTimeval(sec, usec int64) Timeval {
+ return Timeval{Sec: sec, Usec: usec}
}
func SetKevent(k *Kevent_t, fd, mode, flags int) {
@@ -35,6 +28,14 @@ func (msghdr *Msghdr) SetControllen(length int) {
msghdr.Controllen = uint32(length)
}
+func (msghdr *Msghdr) SetIovlen(length int) {
+ msghdr.Iovlen = uint32(length)
+}
+
func (cmsg *Cmsghdr) SetLen(length int) {
cmsg.Len = uint32(length)
}
+
+// SYS___SYSCTL is used by syscall_bsd.go for all BSDs, but in modern versions
+// of openbsd/amd64 the syscall is called sysctl instead of __sysctl.
+const SYS___SYSCTL = SYS_SYSCTL
diff --git a/vendor/golang.org/x/sys/unix/syscall_openbsd_arm.go b/vendor/golang.org/x/sys/unix/syscall_openbsd_arm.go
index ba86490..1c3d26f 100644
--- a/vendor/golang.org/x/sys/unix/syscall_openbsd_arm.go
+++ b/vendor/golang.org/x/sys/unix/syscall_openbsd_arm.go
@@ -6,19 +6,12 @@
package unix
-func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
-
-func NsecToTimespec(nsec int64) (ts Timespec) {
- ts.Sec = int64(nsec / 1e9)
- ts.Nsec = int32(nsec % 1e9)
- return
+func setTimespec(sec, nsec int64) Timespec {
+ return Timespec{Sec: sec, Nsec: int32(nsec)}
}
-func NsecToTimeval(nsec int64) (tv Timeval) {
- nsec += 999 // round up to microsecond
- tv.Usec = int32(nsec % 1e9 / 1e3)
- tv.Sec = int64(nsec / 1e9)
- return
+func setTimeval(sec, usec int64) Timeval {
+ return Timeval{Sec: sec, Usec: int32(usec)}
}
func SetKevent(k *Kevent_t, fd, mode, flags int) {
@@ -35,6 +28,14 @@ func (msghdr *Msghdr) SetControllen(length int) {
msghdr.Controllen = uint32(length)
}
+func (msghdr *Msghdr) SetIovlen(length int) {
+ msghdr.Iovlen = uint32(length)
+}
+
func (cmsg *Cmsghdr) SetLen(length int) {
cmsg.Len = uint32(length)
}
+
+// SYS___SYSCTL is used by syscall_bsd.go for all BSDs, but in modern versions
+// of openbsd/arm the syscall is called sysctl instead of __sysctl.
+const SYS___SYSCTL = SYS_SYSCTL
diff --git a/vendor/golang.org/x/sys/unix/syscall_openbsd_arm64.go b/vendor/golang.org/x/sys/unix/syscall_openbsd_arm64.go
new file mode 100644
index 0000000..a8c458c
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/syscall_openbsd_arm64.go
@@ -0,0 +1,41 @@
+// Copyright 2019 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 arm64,openbsd
+
+package unix
+
+func setTimespec(sec, nsec int64) Timespec {
+ return Timespec{Sec: sec, Nsec: nsec}
+}
+
+func setTimeval(sec, usec int64) Timeval {
+ return Timeval{Sec: sec, Usec: usec}
+}
+
+func SetKevent(k *Kevent_t, fd, mode, flags int) {
+ k.Ident = uint64(fd)
+ k.Filter = int16(mode)
+ k.Flags = uint16(flags)
+}
+
+func (iov *Iovec) SetLen(length int) {
+ iov.Len = uint64(length)
+}
+
+func (msghdr *Msghdr) SetControllen(length int) {
+ msghdr.Controllen = uint32(length)
+}
+
+func (msghdr *Msghdr) SetIovlen(length int) {
+ msghdr.Iovlen = uint32(length)
+}
+
+func (cmsg *Cmsghdr) SetLen(length int) {
+ cmsg.Len = uint32(length)
+}
+
+// SYS___SYSCTL is used by syscall_bsd.go for all BSDs, but in modern versions
+// of openbsd/amd64 the syscall is called sysctl instead of __sysctl.
+const SYS___SYSCTL = SYS_SYSCTL
diff --git a/vendor/golang.org/x/sys/unix/syscall_solaris.go b/vendor/golang.org/x/sys/unix/syscall_solaris.go
index 35e5d72..0e2a696 100644
--- a/vendor/golang.org/x/sys/unix/syscall_solaris.go
+++ b/vendor/golang.org/x/sys/unix/syscall_solaris.go
@@ -23,6 +23,7 @@ type syscallFunc uintptr
func rawSysvicall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err syscall.Errno)
func sysvicall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err syscall.Errno)
+// SockaddrDatalink implements the Sockaddr interface for AF_LINK type sockets.
type SockaddrDatalink struct {
Family uint16
Index uint16
@@ -34,15 +35,6 @@ type SockaddrDatalink struct {
raw RawSockaddrDatalink
}
-func clen(n []byte) int {
- for i := 0; i < len(n); i++ {
- if n[i] == 0 {
- return i
- }
- }
- return len(n)
-}
-
func direntIno(buf []byte) (uint64, bool) {
return readInt(buf, unsafe.Offsetof(Dirent{}.Ino), unsafe.Sizeof(Dirent{}.Ino))
}
@@ -136,7 +128,19 @@ func Getsockname(fd int) (sa Sockaddr, err error) {
if err = getsockname(fd, &rsa, &len); err != nil {
return
}
- return anyToSockaddr(&rsa)
+ return anyToSockaddr(fd, &rsa)
+}
+
+// GetsockoptString returns the string value of the socket option opt for the
+// socket associated with fd at the given socket level.
+func GetsockoptString(fd, level, opt int) (string, error) {
+ buf := make([]byte, 256)
+ vallen := _Socklen(len(buf))
+ err := getsockopt(fd, level, opt, unsafe.Pointer(&buf[0]), &vallen)
+ if err != nil {
+ return "", err
+ }
+ return string(buf[:vallen-1]), nil
}
const ImplementsGetwd = true
@@ -166,7 +170,7 @@ func Getwd() (wd string, err error) {
func Getgroups() (gids []int, err error) {
n, err := getgroups(0, nil)
- // Check for error and sanity check group count. Newer versions of
+ // Check for error and sanity check group count. Newer versions of
// Solaris allow up to 1024 (NGROUPS_MAX).
if n < 0 || n > 1024 {
if err != nil {
@@ -201,6 +205,7 @@ func Setgroups(gids []int) (err error) {
return setgroups(len(a), &a[0])
}
+// ReadDirent reads directory entries from fd and writes them into buf.
func ReadDirent(fd int, buf []byte) (n int, err error) {
// Final argument is (basep *uintptr) and the syscall doesn't take nil.
// TODO(rsc): Can we use a single global basep for all calls?
@@ -324,6 +329,16 @@ func UtimesNanoAt(dirfd int, path string, ts []Timespec, flags int) error {
//sys fcntl(fd int, cmd int, arg int) (val int, err error)
+// FcntlInt performs a fcntl syscall on fd with the provided command and argument.
+func FcntlInt(fd uintptr, cmd, arg int) (int, error) {
+ valptr, _, errno := sysvicall6(uintptr(unsafe.Pointer(&procfcntl)), 3, uintptr(fd), uintptr(cmd), uintptr(arg), 0, 0, 0)
+ var err error
+ if errno != 0 {
+ err = errno
+ }
+ return int(valptr), err
+}
+
// FcntlFlock performs a fcntl syscall for the F_GETLK, F_SETLK or F_SETLKW command.
func FcntlFlock(fd uintptr, cmd int, lk *Flock_t) error {
_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procfcntl)), 3, uintptr(fd), uintptr(cmd), uintptr(unsafe.Pointer(lk)), 0, 0, 0)
@@ -350,7 +365,7 @@ func Futimesat(dirfd int, path string, tv []Timeval) error {
}
// Solaris doesn't have an futimes function because it allows NULL to be
-// specified as the path for futimesat. However, Go doesn't like
+// specified as the path for futimesat. However, Go doesn't like
// NULL-style string interfaces, so this simple wrapper is provided.
func Futimes(fd int, tv []Timeval) error {
if tv == nil {
@@ -362,7 +377,7 @@ func Futimes(fd int, tv []Timeval) error {
return futimesat(fd, nil, (*[2]Timeval)(unsafe.Pointer(&tv[0])))
}
-func anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, error) {
+func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) {
switch rsa.Addr.Family {
case AF_UNIX:
pp := (*RawSockaddrUnix)(unsafe.Pointer(rsa))
@@ -376,7 +391,7 @@ func anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, error) {
for n < len(pp.Path) && pp.Path[n] != 0 {
n++
}
- bytes := (*[10000]byte)(unsafe.Pointer(&pp.Path[0]))[0:n]
+ bytes := (*[len(pp.Path)]byte)(unsafe.Pointer(&pp.Path[0]))[0:n]
sa.Name = string(bytes)
return sa, nil
@@ -413,7 +428,7 @@ func Accept(fd int) (nfd int, sa Sockaddr, err error) {
if nfd == -1 {
return
}
- sa, err = anyToSockaddr(&rsa)
+ sa, err = anyToSockaddr(fd, &rsa)
if err != nil {
Close(nfd)
nfd = 0
@@ -450,7 +465,7 @@ func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from
oobn = int(msg.Accrightslen)
// source address is only specified if the socket is unconnected
if rsa.Addr.Family != AF_UNSPEC {
- from, err = anyToSockaddr(&rsa)
+ from, err = anyToSockaddr(fd, &rsa)
}
return
}
@@ -538,46 +553,32 @@ func Minor(dev uint64) uint32 {
//sys ioctl(fd int, req uint, arg uintptr) (err error)
-func IoctlSetInt(fd int, req uint, value int) (err error) {
- return ioctl(fd, req, uintptr(value))
-}
-
-func IoctlSetWinsize(fd int, req uint, value *Winsize) (err error) {
- return ioctl(fd, req, uintptr(unsafe.Pointer(value)))
-}
-
-func IoctlSetTermios(fd int, req uint, value *Termios) (err error) {
- return ioctl(fd, req, uintptr(unsafe.Pointer(value)))
-}
-
func IoctlSetTermio(fd int, req uint, value *Termio) (err error) {
return ioctl(fd, req, uintptr(unsafe.Pointer(value)))
}
-func IoctlGetInt(fd int, req uint) (int, error) {
- var value int
- err := ioctl(fd, req, uintptr(unsafe.Pointer(&value)))
- return value, err
-}
-
-func IoctlGetWinsize(fd int, req uint) (*Winsize, error) {
- var value Winsize
- err := ioctl(fd, req, uintptr(unsafe.Pointer(&value)))
- return &value, err
-}
-
-func IoctlGetTermios(fd int, req uint) (*Termios, error) {
- var value Termios
- err := ioctl(fd, req, uintptr(unsafe.Pointer(&value)))
- return &value, err
-}
-
func IoctlGetTermio(fd int, req uint) (*Termio, error) {
var value Termio
err := ioctl(fd, req, uintptr(unsafe.Pointer(&value)))
return &value, err
}
+//sys poll(fds *PollFd, nfds int, timeout int) (n int, err error)
+
+func Poll(fds []PollFd, timeout int) (n int, err error) {
+ if len(fds) == 0 {
+ return poll(nil, 0, timeout)
+ }
+ return poll(&fds[0], len(fds), timeout)
+}
+
+func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
+ if raceenabled {
+ raceReleaseMerge(unsafe.Pointer(&ioSync))
+ }
+ return sendfile(outfd, infd, offset, count)
+}
+
/*
* Exposed directly
*/
@@ -592,15 +593,17 @@ func IoctlGetTermio(fd int, req uint) (*Termio, error) {
//sys Dup(fd int) (nfd int, err error)
//sys Dup2(oldfd int, newfd int) (err error)
//sys Exit(code int)
+//sys Faccessat(dirfd int, path string, mode uint32, flags int) (err error)
//sys Fchdir(fd int) (err error)
//sys Fchmod(fd int, mode uint32) (err error)
//sys Fchmodat(dirfd int, path string, mode uint32, flags int) (err error)
//sys Fchown(fd int, uid int, gid int) (err error)
//sys Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error)
//sys Fdatasync(fd int) (err error)
-//sys Flock(fd int, how int) (err error)
+//sys Flock(fd int, how int) (err error)
//sys Fpathconf(fd int, name int) (val int, err error)
//sys Fstat(fd int, stat *Stat_t) (err error)
+//sys Fstatat(fd int, path string, stat *Stat_t, flags int) (err error)
//sys Fstatvfs(fd int, vfsstat *Statvfs_t) (err error)
//sys Getdents(fd int, buf []byte, basep *uintptr) (n int, err error)
//sysnb Getgid() (gid int)
@@ -646,6 +649,7 @@ func IoctlGetTermio(fd int, req uint) (*Termio, error) {
//sys Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error)
//sys Rmdir(path string) (err error)
//sys Seek(fd int, offset int64, whence int) (newoffset int64, err error) = lseek
+//sys Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err error)
//sysnb Setegid(egid int) (err error)
//sysnb Seteuid(euid int) (err error)
//sysnb Setgid(gid int) (err error)
@@ -677,6 +681,7 @@ func IoctlGetTermio(fd int, req uint) (*Termio, error) {
//sys connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) = libsocket.__xnet_connect
//sys mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error)
//sys munmap(addr uintptr, length uintptr) (err error)
+//sys sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) = libsendfile.sendfile
//sys sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) = libsocket.__xnet_sendto
//sys socket(domain int, typ int, proto int) (fd int, err error) = libsocket.__xnet_socket
//sysnb socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) = libsocket.__xnet_socketpair
diff --git a/vendor/golang.org/x/sys/unix/syscall_solaris_amd64.go b/vendor/golang.org/x/sys/unix/syscall_solaris_amd64.go
index 5aff62c..b22a34d 100644
--- a/vendor/golang.org/x/sys/unix/syscall_solaris_amd64.go
+++ b/vendor/golang.org/x/sys/unix/syscall_solaris_amd64.go
@@ -6,30 +6,22 @@
package unix
-func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
-
-func NsecToTimespec(nsec int64) (ts Timespec) {
- ts.Sec = nsec / 1e9
- ts.Nsec = nsec % 1e9
- return
+func setTimespec(sec, nsec int64) Timespec {
+ return Timespec{Sec: sec, Nsec: nsec}
}
-func NsecToTimeval(nsec int64) (tv Timeval) {
- nsec += 999 // round up to microsecond
- tv.Usec = nsec % 1e9 / 1e3
- tv.Sec = int64(nsec / 1e9)
- return
+func setTimeval(sec, usec int64) Timeval {
+ return Timeval{Sec: sec, Usec: usec}
}
func (iov *Iovec) SetLen(length int) {
iov.Len = uint64(length)
}
+func (msghdr *Msghdr) SetIovlen(length int) {
+ msghdr.Iovlen = int32(length)
+}
+
func (cmsg *Cmsghdr) SetLen(length int) {
cmsg.Len = uint32(length)
}
-
-func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
- // TODO(aram): implement this, see issue 5847.
- panic("unimplemented")
-}
diff --git a/vendor/golang.org/x/sys/unix/syscall_unix.go b/vendor/golang.org/x/sys/unix/syscall_unix.go
index 3ed8a91..3de3756 100644
--- a/vendor/golang.org/x/sys/unix/syscall_unix.go
+++ b/vendor/golang.org/x/sys/unix/syscall_unix.go
@@ -2,12 +2,13 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
package unix
import (
- "runtime"
+ "bytes"
+ "sort"
"sync"
"syscall"
"unsafe"
@@ -19,13 +20,6 @@ var (
Stderr = 2
)
-const (
- darwin64Bit = runtime.GOOS == "darwin" && sizeofPtr == 8
- dragonfly64Bit = runtime.GOOS == "dragonfly" && sizeofPtr == 8
- netbsd32Bit = runtime.GOOS == "netbsd" && sizeofPtr == 4
- solaris64Bit = runtime.GOOS == "solaris" && sizeofPtr == 8
-)
-
// Do the interface allocations only once for common
// Errno values.
var (
@@ -34,6 +28,11 @@ var (
errENOENT error = syscall.ENOENT
)
+var (
+ signalNameMapOnce sync.Once
+ signalNameMap map[string]syscall.Signal
+)
+
// errnoErr returns common boxed Errno values, to prevent
// allocations at runtime.
func errnoErr(e syscall.Errno) error {
@@ -50,6 +49,50 @@ func errnoErr(e syscall.Errno) error {
return e
}
+// ErrnoName returns the error name for error number e.
+func ErrnoName(e syscall.Errno) string {
+ i := sort.Search(len(errorList), func(i int) bool {
+ return errorList[i].num >= e
+ })
+ if i < len(errorList) && errorList[i].num == e {
+ return errorList[i].name
+ }
+ return ""
+}
+
+// SignalName returns the signal name for signal number s.
+func SignalName(s syscall.Signal) string {
+ i := sort.Search(len(signalList), func(i int) bool {
+ return signalList[i].num >= s
+ })
+ if i < len(signalList) && signalList[i].num == s {
+ return signalList[i].name
+ }
+ return ""
+}
+
+// SignalNum returns the syscall.Signal for signal named s,
+// or 0 if a signal with such name is not found.
+// The signal name should start with "SIG".
+func SignalNum(s string) syscall.Signal {
+ signalNameMapOnce.Do(func() {
+ signalNameMap = make(map[string]syscall.Signal)
+ for _, signal := range signalList {
+ signalNameMap[signal.name] = signal.num
+ }
+ })
+ return signalNameMap[s]
+}
+
+// clen returns the index of the first NULL byte in n or len(n) if n contains no NULL byte.
+func clen(n []byte) int {
+ i := bytes.IndexByte(n, 0)
+ if i == -1 {
+ i = len(n)
+ }
+ return i
+}
+
// Mmap manager, for use by operating system-specific implementations.
type mmapper struct {
@@ -138,16 +181,19 @@ func Write(fd int, p []byte) (n int, err error) {
// creation of IPv6 sockets to return EAFNOSUPPORT.
var SocketDisableIPv6 bool
+// Sockaddr represents a socket address.
type Sockaddr interface {
sockaddr() (ptr unsafe.Pointer, len _Socklen, err error) // lowercase; only we can define Sockaddrs
}
+// SockaddrInet4 implements the Sockaddr interface for AF_INET type sockets.
type SockaddrInet4 struct {
Port int
Addr [4]byte
raw RawSockaddrInet4
}
+// SockaddrInet6 implements the Sockaddr interface for AF_INET6 type sockets.
type SockaddrInet6 struct {
Port int
ZoneId uint32
@@ -155,6 +201,7 @@ type SockaddrInet6 struct {
raw RawSockaddrInet6
}
+// SockaddrUnix implements the Sockaddr interface for AF_UNIX type sockets.
type SockaddrUnix struct {
Name string
raw RawSockaddrUnix
@@ -182,7 +229,14 @@ func Getpeername(fd int) (sa Sockaddr, err error) {
if err = getpeername(fd, &rsa, &len); err != nil {
return
}
- return anyToSockaddr(&rsa)
+ return anyToSockaddr(fd, &rsa)
+}
+
+func GetsockoptByte(fd, level, opt int) (value byte, err error) {
+ var n byte
+ vallen := _Socklen(1)
+ err = getsockopt(fd, level, opt, unsafe.Pointer(&n), &vallen)
+ return n, err
}
func GetsockoptInt(fd, level, opt int) (value int, err error) {
@@ -192,6 +246,61 @@ func GetsockoptInt(fd, level, opt int) (value int, err error) {
return int(n), err
}
+func GetsockoptInet4Addr(fd, level, opt int) (value [4]byte, err error) {
+ vallen := _Socklen(4)
+ err = getsockopt(fd, level, opt, unsafe.Pointer(&value[0]), &vallen)
+ return value, err
+}
+
+func GetsockoptIPMreq(fd, level, opt int) (*IPMreq, error) {
+ var value IPMreq
+ vallen := _Socklen(SizeofIPMreq)
+ err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen)
+ return &value, err
+}
+
+func GetsockoptIPv6Mreq(fd, level, opt int) (*IPv6Mreq, error) {
+ var value IPv6Mreq
+ vallen := _Socklen(SizeofIPv6Mreq)
+ err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen)
+ return &value, err
+}
+
+func GetsockoptIPv6MTUInfo(fd, level, opt int) (*IPv6MTUInfo, error) {
+ var value IPv6MTUInfo
+ vallen := _Socklen(SizeofIPv6MTUInfo)
+ err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen)
+ return &value, err
+}
+
+func GetsockoptICMPv6Filter(fd, level, opt int) (*ICMPv6Filter, error) {
+ var value ICMPv6Filter
+ vallen := _Socklen(SizeofICMPv6Filter)
+ err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen)
+ return &value, err
+}
+
+func GetsockoptLinger(fd, level, opt int) (*Linger, error) {
+ var linger Linger
+ vallen := _Socklen(SizeofLinger)
+ err := getsockopt(fd, level, opt, unsafe.Pointer(&linger), &vallen)
+ return &linger, err
+}
+
+func GetsockoptTimeval(fd, level, opt int) (*Timeval, error) {
+ var tv Timeval
+ vallen := _Socklen(unsafe.Sizeof(tv))
+ err := getsockopt(fd, level, opt, unsafe.Pointer(&tv), &vallen)
+ return &tv, err
+}
+
+func GetsockoptUint64(fd, level, opt int) (value uint64, err error) {
+ var n uint64
+ vallen := _Socklen(8)
+ err = getsockopt(fd, level, opt, unsafe.Pointer(&n), &vallen)
+ return n, err
+}
+
func Recvfrom(fd int, p []byte, flags int) (n int, from Sockaddr, err error) {
var rsa RawSockaddrAny
var len _Socklen = SizeofSockaddrAny
@@ -199,7 +308,7 @@ func Recvfrom(fd int, p []byte, flags int) (n int, from Sockaddr, err error) {
return
}
if rsa.Addr.Family != AF_UNSPEC {
- from, err = anyToSockaddr(&rsa)
+ from, err = anyToSockaddr(fd, &rsa)
}
return
}
@@ -242,13 +351,21 @@ func SetsockoptLinger(fd, level, opt int, l *Linger) (err error) {
}
func SetsockoptString(fd, level, opt int, s string) (err error) {
- return setsockopt(fd, level, opt, unsafe.Pointer(&[]byte(s)[0]), uintptr(len(s)))
+ var p unsafe.Pointer
+ if len(s) > 0 {
+ p = unsafe.Pointer(&[]byte(s)[0])
+ }
+ return setsockopt(fd, level, opt, p, uintptr(len(s)))
}
func SetsockoptTimeval(fd, level, opt int, tv *Timeval) (err error) {
return setsockopt(fd, level, opt, unsafe.Pointer(tv), unsafe.Sizeof(*tv))
}
+func SetsockoptUint64(fd, level, opt int, value uint64) (err error) {
+ return setsockopt(fd, level, opt, unsafe.Pointer(&value), 8)
+}
+
func Socket(domain, typ, proto int) (fd int, err error) {
if domain == AF_INET6 && SocketDisableIPv6 {
return -1, EAFNOSUPPORT
@@ -267,13 +384,6 @@ func Socketpair(domain, typ, proto int) (fd [2]int, err error) {
return
}
-func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
- if raceenabled {
- raceReleaseMerge(unsafe.Pointer(&ioSync))
- }
- return sendfile(outfd, infd, offset, count)
-}
-
var ioSync int64
func CloseOnExec(fd int) { fcntl(fd, F_SETFD, FD_CLOEXEC) }
@@ -291,3 +401,31 @@ func SetNonblock(fd int, nonblocking bool) (err error) {
_, err = fcntl(fd, F_SETFL, flag)
return err
}
+
+// Exec calls execve(2), which replaces the calling executable in the process
+// tree. argv0 should be the full path to an executable ("/bin/ls") and the
+// executable name should also be the first argument in argv (["ls", "-l"]).
+// envv are the environment variables that should be passed to the new
+// process (["USER=go", "PWD=/tmp"]).
+func Exec(argv0 string, argv []string, envv []string) error {
+ return syscall.Exec(argv0, argv, envv)
+}
+
+// Lutimes sets the access and modification times tv on path. If path refers to
+// a symlink, it is not dereferenced and the timestamps are set on the symlink.
+// If tv is nil, the access and modification times are set to the current time.
+// Otherwise tv must contain exactly 2 elements, with access time as the first
+// element and modification time as the second element.
+func Lutimes(path string, tv []Timeval) error {
+ if tv == nil {
+ return UtimesNanoAt(AT_FDCWD, path, nil, AT_SYMLINK_NOFOLLOW)
+ }
+ if len(tv) != 2 {
+ return EINVAL
+ }
+ ts := []Timespec{
+ NsecToTimespec(TimevalToNsec(tv[0])),
+ NsecToTimespec(TimevalToNsec(tv[1])),
+ }
+ return UtimesNanoAt(AT_FDCWD, path, ts, AT_SYMLINK_NOFOLLOW)
+}
diff --git a/vendor/golang.org/x/sys/unix/syscall_unix_gc.go b/vendor/golang.org/x/sys/unix/syscall_unix_gc.go
index 4cb8e8e..1c70d1b 100644
--- a/vendor/golang.org/x/sys/unix/syscall_unix_gc.go
+++ b/vendor/golang.org/x/sys/unix/syscall_unix_gc.go
@@ -3,7 +3,7 @@
// license that can be found in the LICENSE file.
// +build darwin dragonfly freebsd linux netbsd openbsd solaris
-// +build !gccgo
+// +build !gccgo,!ppc64le,!ppc64
package unix
diff --git a/vendor/golang.org/x/sys/unix/syscall_unix_gc_ppc64x.go b/vendor/golang.org/x/sys/unix/syscall_unix_gc_ppc64x.go
new file mode 100644
index 0000000..86dc765
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/syscall_unix_gc_ppc64x.go
@@ -0,0 +1,24 @@
+// Copyright 2018 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 linux
+// +build ppc64le ppc64
+// +build !gccgo
+
+package unix
+
+import "syscall"
+
+func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) {
+ return syscall.Syscall(trap, a1, a2, a3)
+}
+func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err syscall.Errno) {
+ return syscall.Syscall6(trap, a1, a2, a3, a4, a5, a6)
+}
+func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) {
+ return syscall.RawSyscall(trap, a1, a2, a3)
+}
+func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err syscall.Errno) {
+ return syscall.RawSyscall6(trap, a1, a2, a3, a4, a5, a6)
+}
diff --git a/vendor/golang.org/x/sys/unix/timestruct.go b/vendor/golang.org/x/sys/unix/timestruct.go
new file mode 100644
index 0000000..4a672f5
--- /dev/null
+++ b/vendor/golang.org/x/sys/unix/timestruct.go
@@ -0,0 +1,82 @@
+// 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 aix darwin dragonfly freebsd linux netbsd openbsd solaris
+
+package unix
+
+import "time"
+
+// TimespecToNsec converts a Timespec value into a number of
+// nanoseconds since the Unix epoch.
+func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
+
+// NsecToTimespec takes a number of nanoseconds since the Unix epoch
+// and returns the corresponding Timespec value.
+func NsecToTimespec(nsec int64) Timespec {
+ sec := nsec / 1e9
+ nsec = nsec % 1e9
+ if nsec < 0 {
+ nsec += 1e9
+ sec--
+ }
+ return setTimespec(sec, nsec)
+}
+
+// TimeToTimespec converts t into a Timespec.
+// On some 32-bit systems the range of valid Timespec values are smaller
+// than that of time.Time values. So if t is out of the valid range of
+// Timespec, it returns a zero Timespec and ERANGE.
+func TimeToTimespec(t time.Time) (Timespec, error) {
+ sec := t.Unix()
+ nsec := int64(t.Nanosecond())
+ ts := setTimespec(sec, nsec)
+
+ // Currently all targets have either int32 or int64 for Timespec.Sec.
+ // If there were a new target with floating point type for it, we have
+ // to consider the rounding error.
+ if int64(ts.Sec) != sec {
+ return Timespec{}, ERANGE
+ }
+ return ts, nil
+}
+
+// TimevalToNsec converts a Timeval value into a number of nanoseconds
+// since the Unix epoch.
+func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
+
+// NsecToTimeval takes a number of nanoseconds since the Unix epoch
+// and returns the corresponding Timeval value.
+func NsecToTimeval(nsec int64) Timeval {
+ nsec += 999 // round up to microsecond
+ usec := nsec % 1e9 / 1e3
+ sec := nsec / 1e9
+ if usec < 0 {
+ usec += 1e6
+ sec--
+ }
+ return setTimeval(sec, usec)
+}
+
+// Unix returns ts as the number of seconds and nanoseconds elapsed since the
+// Unix epoch.
+func (ts *Timespec) Unix() (sec int64, nsec int64) {
+ return int64(ts.Sec), int64(ts.Nsec)
+}
+
+// Unix returns tv as the number of seconds and nanoseconds elapsed since the
+// Unix epoch.
+func (tv *Timeval) Unix() (sec int64, nsec int64) {
+ return int64(tv.Sec), int64(tv.Usec) * 1000
+}
+
+// Nano returns ts as the number of nanoseconds elapsed since the Unix epoch.
+func (ts *Timespec) Nano() int64 {
+ return int64(ts.Sec)*1e9 + int64(ts.Nsec)
+}
+
+// Nano returns tv as the number of nanoseconds elapsed since the Unix epoch.
+func (tv *Timeval) Nano() int64 {
+ return int64(tv.Sec)*1e9 + int64(tv.Usec)*1000
+}
diff --git a/vendor/golang.org/x/sys/unix/types_darwin.go b/vendor/golang.org/x/sys/unix/types_darwin.go
deleted file mode 100644
index 415124d..0000000
--- a/vendor/golang.org/x/sys/unix/types_darwin.go
+++ /dev/null
@@ -1,254 +0,0 @@
-// 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.
-
-// +build ignore
-
-/*
-Input to cgo -godefs. See README.md
-*/
-
-// +godefs map struct_in_addr [4]byte /* in_addr */
-// +godefs map struct_in6_addr [16]byte /* in6_addr */
-
-package unix
-
-/*
-#define __DARWIN_UNIX03 0
-#define KERNEL
-#define _DARWIN_USE_64_BIT_INODE
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include