增加vendor
This commit is contained in:
190
vendor/github.com/moby/locker/LICENSE
generated
vendored
Normal file
190
vendor/github.com/moby/locker/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,190 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
https://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Copyright 2013-2018 Docker, Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
65
vendor/github.com/moby/locker/README.md
generated
vendored
Normal file
65
vendor/github.com/moby/locker/README.md
generated
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
Locker
|
||||
=====
|
||||
|
||||
locker provides a mechanism for creating finer-grained locking to help
|
||||
free up more global locks to handle other tasks.
|
||||
|
||||
The implementation looks close to a sync.Mutex, however, the user must provide a
|
||||
reference to use to refer to the underlying lock when locking and unlocking,
|
||||
and unlock may generate an error.
|
||||
|
||||
If a lock with a given name does not exist when `Lock` is called, one is
|
||||
created.
|
||||
Lock references are automatically cleaned up on `Unlock` if nothing else is
|
||||
waiting for the lock.
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
```go
|
||||
package important
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/moby/locker"
|
||||
)
|
||||
|
||||
type important struct {
|
||||
locks *locker.Locker
|
||||
data map[string]interface{}
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
func (i *important) Get(name string) interface{} {
|
||||
i.locks.Lock(name)
|
||||
defer i.locks.Unlock(name)
|
||||
return i.data[name]
|
||||
}
|
||||
|
||||
func (i *important) Create(name string, data interface{}) {
|
||||
i.locks.Lock(name)
|
||||
defer i.locks.Unlock(name)
|
||||
|
||||
i.createImportant(data)
|
||||
|
||||
i.mu.Lock()
|
||||
i.data[name] = data
|
||||
i.mu.Unlock()
|
||||
}
|
||||
|
||||
func (i *important) createImportant(data interface{}) {
|
||||
time.Sleep(10 * time.Second)
|
||||
}
|
||||
```
|
||||
|
||||
For functions dealing with a given name, always lock at the beginning of the
|
||||
function (or before doing anything with the underlying state), this ensures any
|
||||
other function that is dealing with the same name will block.
|
||||
|
||||
When needing to modify the underlying data, use the global lock to ensure nothing
|
||||
else is modifying it at the same time.
|
||||
Since name lock is already in place, no reads will occur while the modification
|
||||
is being performed.
|
||||
|
||||
112
vendor/github.com/moby/locker/locker.go
generated
vendored
Normal file
112
vendor/github.com/moby/locker/locker.go
generated
vendored
Normal file
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
Package locker provides a mechanism for creating finer-grained locking to help
|
||||
free up more global locks to handle other tasks.
|
||||
|
||||
The implementation looks close to a sync.Mutex, however the user must provide a
|
||||
reference to use to refer to the underlying lock when locking and unlocking,
|
||||
and unlock may generate an error.
|
||||
|
||||
If a lock with a given name does not exist when `Lock` is called, one is
|
||||
created.
|
||||
Lock references are automatically cleaned up on `Unlock` if nothing else is
|
||||
waiting for the lock.
|
||||
*/
|
||||
package locker
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
// ErrNoSuchLock is returned when the requested lock does not exist
|
||||
var ErrNoSuchLock = errors.New("no such lock")
|
||||
|
||||
// Locker provides a locking mechanism based on the passed in reference name
|
||||
type Locker struct {
|
||||
mu sync.Mutex
|
||||
locks map[string]*lockCtr
|
||||
}
|
||||
|
||||
// lockCtr is used by Locker to represent a lock with a given name.
|
||||
type lockCtr struct {
|
||||
mu sync.Mutex
|
||||
// waiters is the number of waiters waiting to acquire the lock
|
||||
// this is int32 instead of uint32 so we can add `-1` in `dec()`
|
||||
waiters int32
|
||||
}
|
||||
|
||||
// inc increments the number of waiters waiting for the lock
|
||||
func (l *lockCtr) inc() {
|
||||
atomic.AddInt32(&l.waiters, 1)
|
||||
}
|
||||
|
||||
// dec decrements the number of waiters waiting on the lock
|
||||
func (l *lockCtr) dec() {
|
||||
atomic.AddInt32(&l.waiters, -1)
|
||||
}
|
||||
|
||||
// count gets the current number of waiters
|
||||
func (l *lockCtr) count() int32 {
|
||||
return atomic.LoadInt32(&l.waiters)
|
||||
}
|
||||
|
||||
// Lock locks the mutex
|
||||
func (l *lockCtr) Lock() {
|
||||
l.mu.Lock()
|
||||
}
|
||||
|
||||
// Unlock unlocks the mutex
|
||||
func (l *lockCtr) Unlock() {
|
||||
l.mu.Unlock()
|
||||
}
|
||||
|
||||
// New creates a new Locker
|
||||
func New() *Locker {
|
||||
return &Locker{
|
||||
locks: make(map[string]*lockCtr),
|
||||
}
|
||||
}
|
||||
|
||||
// Lock locks a mutex with the given name. If it doesn't exist, one is created
|
||||
func (l *Locker) Lock(name string) {
|
||||
l.mu.Lock()
|
||||
if l.locks == nil {
|
||||
l.locks = make(map[string]*lockCtr)
|
||||
}
|
||||
|
||||
nameLock, exists := l.locks[name]
|
||||
if !exists {
|
||||
nameLock = &lockCtr{}
|
||||
l.locks[name] = nameLock
|
||||
}
|
||||
|
||||
// increment the nameLock waiters while inside the main mutex
|
||||
// this makes sure that the lock isn't deleted if `Lock` and `Unlock` are called concurrently
|
||||
nameLock.inc()
|
||||
l.mu.Unlock()
|
||||
|
||||
// Lock the nameLock outside the main mutex so we don't block other operations
|
||||
// once locked then we can decrement the number of waiters for this lock
|
||||
nameLock.Lock()
|
||||
nameLock.dec()
|
||||
}
|
||||
|
||||
// Unlock unlocks the mutex with the given name
|
||||
// If the given lock is not being waited on by any other callers, it is deleted
|
||||
func (l *Locker) Unlock(name string) error {
|
||||
l.mu.Lock()
|
||||
nameLock, exists := l.locks[name]
|
||||
if !exists {
|
||||
l.mu.Unlock()
|
||||
return ErrNoSuchLock
|
||||
}
|
||||
|
||||
if nameLock.count() == 0 {
|
||||
delete(l.locks, name)
|
||||
}
|
||||
nameLock.Unlock()
|
||||
|
||||
l.mu.Unlock()
|
||||
return nil
|
||||
}
|
||||
13
vendor/github.com/moby/spdystream/CONTRIBUTING.md
generated
vendored
Normal file
13
vendor/github.com/moby/spdystream/CONTRIBUTING.md
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
# Contributing to SpdyStream
|
||||
|
||||
Want to hack on spdystream? Awesome! Here are instructions to get you
|
||||
started.
|
||||
|
||||
SpdyStream is a part of the [Docker](https://docker.io) project, and follows
|
||||
the same rules and principles. If you're already familiar with the way
|
||||
Docker does things, you'll feel right at home.
|
||||
|
||||
Otherwise, go read
|
||||
[Docker's contributions guidelines](https://github.com/dotcloud/docker/blob/master/CONTRIBUTING.md).
|
||||
|
||||
Happy hacking!
|
||||
202
vendor/github.com/moby/spdystream/LICENSE
generated
vendored
Normal file
202
vendor/github.com/moby/spdystream/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
40
vendor/github.com/moby/spdystream/MAINTAINERS
generated
vendored
Normal file
40
vendor/github.com/moby/spdystream/MAINTAINERS
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
# Spdystream maintainers file
|
||||
#
|
||||
# This file describes who runs the moby/spdystream project and how.
|
||||
# This is a living document - if you see something out of date or missing, speak up!
|
||||
#
|
||||
# It is structured to be consumable by both humans and programs.
|
||||
# To extract its contents programmatically, use any TOML-compliant parser.
|
||||
#
|
||||
# This file is compiled into the MAINTAINERS file in docker/opensource.
|
||||
#
|
||||
[Org]
|
||||
[Org."Core maintainers"]
|
||||
people = [
|
||||
"adisky",
|
||||
"dims",
|
||||
"dmcgowan",
|
||||
]
|
||||
|
||||
[people]
|
||||
|
||||
# A reference list of all people associated with the project.
|
||||
# All other sections should refer to people by their canonical key
|
||||
# in the people section.
|
||||
|
||||
# ADD YOURSELF HERE IN ALPHABETICAL ORDER
|
||||
|
||||
[people.adisky]
|
||||
Name = "Aditi Sharma"
|
||||
Email = "adi.sky17@gmail.com"
|
||||
GitHub = "adisky"
|
||||
|
||||
[people.dims]
|
||||
Name = "Davanum Srinivas"
|
||||
Email = "davanum@gmail.com"
|
||||
GitHub = "dims"
|
||||
|
||||
[people.dmcgowan]
|
||||
Name = "Derek McGowan"
|
||||
Email = "derek@mcg.dev"
|
||||
GitHub = "dmcgowan"
|
||||
5
vendor/github.com/moby/spdystream/NOTICE
generated
vendored
Normal file
5
vendor/github.com/moby/spdystream/NOTICE
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
SpdyStream
|
||||
Copyright 2014-2021 Docker Inc.
|
||||
|
||||
This product includes software developed at
|
||||
Docker Inc. (https://www.docker.com/).
|
||||
77
vendor/github.com/moby/spdystream/README.md
generated
vendored
Normal file
77
vendor/github.com/moby/spdystream/README.md
generated
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
# SpdyStream
|
||||
|
||||
A multiplexed stream library using spdy
|
||||
|
||||
## Usage
|
||||
|
||||
Client example (connecting to mirroring server without auth)
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/moby/spdystream"
|
||||
"net"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func main() {
|
||||
conn, err := net.Dial("tcp", "localhost:8080")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
spdyConn, err := spdystream.NewConnection(conn, false)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
go spdyConn.Serve(spdystream.NoOpStreamHandler)
|
||||
stream, err := spdyConn.CreateStream(http.Header{}, nil, false)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
stream.Wait()
|
||||
|
||||
fmt.Fprint(stream, "Writing to stream")
|
||||
|
||||
buf := make([]byte, 25)
|
||||
stream.Read(buf)
|
||||
fmt.Println(string(buf))
|
||||
|
||||
stream.Close()
|
||||
}
|
||||
```
|
||||
|
||||
Server example (mirroring server without auth)
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/moby/spdystream"
|
||||
"net"
|
||||
)
|
||||
|
||||
func main() {
|
||||
listener, err := net.Listen("tcp", "localhost:8080")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
for {
|
||||
conn, err := listener.Accept()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
spdyConn, err := spdystream.NewConnection(conn, true)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
go spdyConn.Serve(spdystream.MirrorStreamHandler)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Copyright and license
|
||||
|
||||
Copyright 2013-2021 Docker, inc. Released under the [Apache 2.0 license](LICENSE).
|
||||
972
vendor/github.com/moby/spdystream/connection.go
generated
vendored
Normal file
972
vendor/github.com/moby/spdystream/connection.go
generated
vendored
Normal file
@@ -0,0 +1,972 @@
|
||||
/*
|
||||
Copyright 2014-2021 Docker Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package spdystream
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/moby/spdystream/spdy"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrInvalidStreamId = errors.New("Invalid stream id")
|
||||
ErrTimeout = errors.New("Timeout occurred")
|
||||
ErrReset = errors.New("Stream reset")
|
||||
ErrWriteClosedStream = errors.New("Write on closed stream")
|
||||
)
|
||||
|
||||
const (
|
||||
FRAME_WORKERS = 5
|
||||
QUEUE_SIZE = 50
|
||||
)
|
||||
|
||||
type StreamHandler func(stream *Stream)
|
||||
|
||||
type AuthHandler func(header http.Header, slot uint8, parent uint32) bool
|
||||
|
||||
type idleAwareFramer struct {
|
||||
f *spdy.Framer
|
||||
conn *Connection
|
||||
writeLock sync.Mutex
|
||||
resetChan chan struct{}
|
||||
setTimeoutLock sync.Mutex
|
||||
setTimeoutChan chan time.Duration
|
||||
timeout time.Duration
|
||||
}
|
||||
|
||||
func newIdleAwareFramer(framer *spdy.Framer) *idleAwareFramer {
|
||||
iaf := &idleAwareFramer{
|
||||
f: framer,
|
||||
resetChan: make(chan struct{}, 2),
|
||||
// setTimeoutChan needs to be buffered to avoid deadlocks when calling setIdleTimeout at about
|
||||
// the same time the connection is being closed
|
||||
setTimeoutChan: make(chan time.Duration, 1),
|
||||
}
|
||||
return iaf
|
||||
}
|
||||
|
||||
func (i *idleAwareFramer) monitor() {
|
||||
var (
|
||||
timer *time.Timer
|
||||
expired <-chan time.Time
|
||||
resetChan = i.resetChan
|
||||
setTimeoutChan = i.setTimeoutChan
|
||||
)
|
||||
Loop:
|
||||
for {
|
||||
select {
|
||||
case timeout := <-i.setTimeoutChan:
|
||||
i.timeout = timeout
|
||||
if timeout == 0 {
|
||||
if timer != nil {
|
||||
timer.Stop()
|
||||
}
|
||||
} else {
|
||||
if timer == nil {
|
||||
timer = time.NewTimer(timeout)
|
||||
expired = timer.C
|
||||
} else {
|
||||
timer.Reset(timeout)
|
||||
}
|
||||
}
|
||||
case <-resetChan:
|
||||
if timer != nil && i.timeout > 0 {
|
||||
timer.Reset(i.timeout)
|
||||
}
|
||||
case <-expired:
|
||||
i.conn.streamCond.L.Lock()
|
||||
streams := i.conn.streams
|
||||
i.conn.streams = make(map[spdy.StreamId]*Stream)
|
||||
i.conn.streamCond.Broadcast()
|
||||
i.conn.streamCond.L.Unlock()
|
||||
go func() {
|
||||
for _, stream := range streams {
|
||||
stream.resetStream()
|
||||
}
|
||||
i.conn.Close()
|
||||
}()
|
||||
case <-i.conn.closeChan:
|
||||
if timer != nil {
|
||||
timer.Stop()
|
||||
}
|
||||
|
||||
// Start a goroutine to drain resetChan. This is needed because we've seen
|
||||
// some unit tests with large numbers of goroutines get into a situation
|
||||
// where resetChan fills up, at least 1 call to Write() is still trying to
|
||||
// send to resetChan, the connection gets closed, and this case statement
|
||||
// attempts to grab the write lock that Write() already has, causing a
|
||||
// deadlock.
|
||||
//
|
||||
// See https://github.com/moby/spdystream/issues/49 for more details.
|
||||
go func() {
|
||||
for range resetChan {
|
||||
}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
for range setTimeoutChan {
|
||||
}
|
||||
}()
|
||||
|
||||
i.writeLock.Lock()
|
||||
close(resetChan)
|
||||
i.resetChan = nil
|
||||
i.writeLock.Unlock()
|
||||
|
||||
i.setTimeoutLock.Lock()
|
||||
close(i.setTimeoutChan)
|
||||
i.setTimeoutChan = nil
|
||||
i.setTimeoutLock.Unlock()
|
||||
|
||||
break Loop
|
||||
}
|
||||
}
|
||||
|
||||
// Drain resetChan
|
||||
for range resetChan {
|
||||
}
|
||||
}
|
||||
|
||||
func (i *idleAwareFramer) WriteFrame(frame spdy.Frame) error {
|
||||
i.writeLock.Lock()
|
||||
defer i.writeLock.Unlock()
|
||||
if i.resetChan == nil {
|
||||
return io.EOF
|
||||
}
|
||||
err := i.f.WriteFrame(frame)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
i.resetChan <- struct{}{}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *idleAwareFramer) ReadFrame() (spdy.Frame, error) {
|
||||
frame, err := i.f.ReadFrame()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// resetChan should never be closed since it is only closed
|
||||
// when the connection has closed its closeChan. This closure
|
||||
// only occurs after all Reads have finished
|
||||
// TODO (dmcgowan): refactor relationship into connection
|
||||
i.resetChan <- struct{}{}
|
||||
|
||||
return frame, nil
|
||||
}
|
||||
|
||||
func (i *idleAwareFramer) setIdleTimeout(timeout time.Duration) {
|
||||
i.setTimeoutLock.Lock()
|
||||
defer i.setTimeoutLock.Unlock()
|
||||
|
||||
if i.setTimeoutChan == nil {
|
||||
return
|
||||
}
|
||||
|
||||
i.setTimeoutChan <- timeout
|
||||
}
|
||||
|
||||
type Connection struct {
|
||||
conn net.Conn
|
||||
framer *idleAwareFramer
|
||||
|
||||
closeChan chan bool
|
||||
goneAway bool
|
||||
lastStreamChan chan<- *Stream
|
||||
goAwayTimeout time.Duration
|
||||
closeTimeout time.Duration
|
||||
|
||||
streamLock *sync.RWMutex
|
||||
streamCond *sync.Cond
|
||||
streams map[spdy.StreamId]*Stream
|
||||
|
||||
nextIdLock sync.Mutex
|
||||
receiveIdLock sync.Mutex
|
||||
nextStreamId spdy.StreamId
|
||||
receivedStreamId spdy.StreamId
|
||||
|
||||
pingIdLock sync.Mutex
|
||||
pingId uint32
|
||||
pingChans map[uint32]chan error
|
||||
|
||||
shutdownLock sync.Mutex
|
||||
shutdownChan chan error
|
||||
hasShutdown bool
|
||||
|
||||
// for testing https://github.com/moby/spdystream/pull/56
|
||||
dataFrameHandler func(*spdy.DataFrame) error
|
||||
}
|
||||
|
||||
// NewConnection creates a new spdy connection from an existing
|
||||
// network connection.
|
||||
func NewConnection(conn net.Conn, server bool) (*Connection, error) {
|
||||
framer, framerErr := spdy.NewFramer(conn, conn)
|
||||
if framerErr != nil {
|
||||
return nil, framerErr
|
||||
}
|
||||
idleAwareFramer := newIdleAwareFramer(framer)
|
||||
var sid spdy.StreamId
|
||||
var rid spdy.StreamId
|
||||
var pid uint32
|
||||
if server {
|
||||
sid = 2
|
||||
rid = 1
|
||||
pid = 2
|
||||
} else {
|
||||
sid = 1
|
||||
rid = 2
|
||||
pid = 1
|
||||
}
|
||||
|
||||
streamLock := new(sync.RWMutex)
|
||||
streamCond := sync.NewCond(streamLock)
|
||||
|
||||
session := &Connection{
|
||||
conn: conn,
|
||||
framer: idleAwareFramer,
|
||||
|
||||
closeChan: make(chan bool),
|
||||
goAwayTimeout: time.Duration(0),
|
||||
closeTimeout: time.Duration(0),
|
||||
|
||||
streamLock: streamLock,
|
||||
streamCond: streamCond,
|
||||
streams: make(map[spdy.StreamId]*Stream),
|
||||
nextStreamId: sid,
|
||||
receivedStreamId: rid,
|
||||
|
||||
pingId: pid,
|
||||
pingChans: make(map[uint32]chan error),
|
||||
|
||||
shutdownChan: make(chan error),
|
||||
}
|
||||
session.dataFrameHandler = session.handleDataFrame
|
||||
idleAwareFramer.conn = session
|
||||
go idleAwareFramer.monitor()
|
||||
|
||||
return session, nil
|
||||
}
|
||||
|
||||
// Ping sends a ping frame across the connection and
|
||||
// returns the response time
|
||||
func (s *Connection) Ping() (time.Duration, error) {
|
||||
pid := s.pingId
|
||||
s.pingIdLock.Lock()
|
||||
if s.pingId > 0x7ffffffe {
|
||||
s.pingId = s.pingId - 0x7ffffffe
|
||||
} else {
|
||||
s.pingId = s.pingId + 2
|
||||
}
|
||||
s.pingIdLock.Unlock()
|
||||
pingChan := make(chan error)
|
||||
s.pingChans[pid] = pingChan
|
||||
defer delete(s.pingChans, pid)
|
||||
|
||||
frame := &spdy.PingFrame{Id: pid}
|
||||
startTime := time.Now()
|
||||
writeErr := s.framer.WriteFrame(frame)
|
||||
if writeErr != nil {
|
||||
return time.Duration(0), writeErr
|
||||
}
|
||||
select {
|
||||
case <-s.closeChan:
|
||||
return time.Duration(0), errors.New("connection closed")
|
||||
case err, ok := <-pingChan:
|
||||
if ok && err != nil {
|
||||
return time.Duration(0), err
|
||||
}
|
||||
break
|
||||
}
|
||||
return time.Since(startTime), nil
|
||||
}
|
||||
|
||||
// Serve handles frames sent from the server, including reply frames
|
||||
// which are needed to fully initiate connections. Both clients and servers
|
||||
// should call Serve in a separate goroutine before creating streams.
|
||||
func (s *Connection) Serve(newHandler StreamHandler) {
|
||||
// use a WaitGroup to wait for all frames to be drained after receiving
|
||||
// go-away.
|
||||
var wg sync.WaitGroup
|
||||
|
||||
// Parition queues to ensure stream frames are handled
|
||||
// by the same worker, ensuring order is maintained
|
||||
frameQueues := make([]*PriorityFrameQueue, FRAME_WORKERS)
|
||||
for i := 0; i < FRAME_WORKERS; i++ {
|
||||
frameQueues[i] = NewPriorityFrameQueue(QUEUE_SIZE)
|
||||
|
||||
// Ensure frame queue is drained when connection is closed
|
||||
go func(frameQueue *PriorityFrameQueue) {
|
||||
<-s.closeChan
|
||||
frameQueue.Drain()
|
||||
}(frameQueues[i])
|
||||
|
||||
wg.Add(1)
|
||||
go func(frameQueue *PriorityFrameQueue) {
|
||||
// let the WaitGroup know this worker is done
|
||||
defer wg.Done()
|
||||
|
||||
s.frameHandler(frameQueue, newHandler)
|
||||
}(frameQueues[i])
|
||||
}
|
||||
|
||||
var (
|
||||
partitionRoundRobin int
|
||||
goAwayFrame *spdy.GoAwayFrame
|
||||
)
|
||||
Loop:
|
||||
for {
|
||||
readFrame, err := s.framer.ReadFrame()
|
||||
if err != nil {
|
||||
if err != io.EOF {
|
||||
debugMessage("frame read error: %s", err)
|
||||
} else {
|
||||
debugMessage("(%p) EOF received", s)
|
||||
}
|
||||
break
|
||||
}
|
||||
var priority uint8
|
||||
var partition int
|
||||
switch frame := readFrame.(type) {
|
||||
case *spdy.SynStreamFrame:
|
||||
if s.checkStreamFrame(frame) {
|
||||
priority = frame.Priority
|
||||
partition = int(frame.StreamId % FRAME_WORKERS)
|
||||
debugMessage("(%p) Add stream frame: %d ", s, frame.StreamId)
|
||||
s.addStreamFrame(frame)
|
||||
} else {
|
||||
debugMessage("(%p) Rejected stream frame: %d ", s, frame.StreamId)
|
||||
continue
|
||||
}
|
||||
case *spdy.SynReplyFrame:
|
||||
priority = s.getStreamPriority(frame.StreamId)
|
||||
partition = int(frame.StreamId % FRAME_WORKERS)
|
||||
case *spdy.DataFrame:
|
||||
priority = s.getStreamPriority(frame.StreamId)
|
||||
partition = int(frame.StreamId % FRAME_WORKERS)
|
||||
case *spdy.RstStreamFrame:
|
||||
priority = s.getStreamPriority(frame.StreamId)
|
||||
partition = int(frame.StreamId % FRAME_WORKERS)
|
||||
case *spdy.HeadersFrame:
|
||||
priority = s.getStreamPriority(frame.StreamId)
|
||||
partition = int(frame.StreamId % FRAME_WORKERS)
|
||||
case *spdy.PingFrame:
|
||||
priority = 0
|
||||
partition = partitionRoundRobin
|
||||
partitionRoundRobin = (partitionRoundRobin + 1) % FRAME_WORKERS
|
||||
case *spdy.GoAwayFrame:
|
||||
// hold on to the go away frame and exit the loop
|
||||
goAwayFrame = frame
|
||||
break Loop
|
||||
default:
|
||||
priority = 7
|
||||
partition = partitionRoundRobin
|
||||
partitionRoundRobin = (partitionRoundRobin + 1) % FRAME_WORKERS
|
||||
}
|
||||
frameQueues[partition].Push(readFrame, priority)
|
||||
}
|
||||
close(s.closeChan)
|
||||
|
||||
// wait for all frame handler workers to indicate they've drained their queues
|
||||
// before handling the go away frame
|
||||
wg.Wait()
|
||||
|
||||
if goAwayFrame != nil {
|
||||
s.handleGoAwayFrame(goAwayFrame)
|
||||
}
|
||||
|
||||
// now it's safe to close remote channels and empty s.streams
|
||||
s.streamCond.L.Lock()
|
||||
// notify streams that they're now closed, which will
|
||||
// unblock any stream Read() calls
|
||||
for _, stream := range s.streams {
|
||||
stream.closeRemoteChannels()
|
||||
}
|
||||
s.streams = make(map[spdy.StreamId]*Stream)
|
||||
s.streamCond.Broadcast()
|
||||
s.streamCond.L.Unlock()
|
||||
}
|
||||
|
||||
func (s *Connection) frameHandler(frameQueue *PriorityFrameQueue, newHandler StreamHandler) {
|
||||
for {
|
||||
popFrame := frameQueue.Pop()
|
||||
if popFrame == nil {
|
||||
return
|
||||
}
|
||||
|
||||
var frameErr error
|
||||
switch frame := popFrame.(type) {
|
||||
case *spdy.SynStreamFrame:
|
||||
frameErr = s.handleStreamFrame(frame, newHandler)
|
||||
case *spdy.SynReplyFrame:
|
||||
frameErr = s.handleReplyFrame(frame)
|
||||
case *spdy.DataFrame:
|
||||
frameErr = s.dataFrameHandler(frame)
|
||||
case *spdy.RstStreamFrame:
|
||||
frameErr = s.handleResetFrame(frame)
|
||||
case *spdy.HeadersFrame:
|
||||
frameErr = s.handleHeaderFrame(frame)
|
||||
case *spdy.PingFrame:
|
||||
frameErr = s.handlePingFrame(frame)
|
||||
case *spdy.GoAwayFrame:
|
||||
frameErr = s.handleGoAwayFrame(frame)
|
||||
default:
|
||||
frameErr = fmt.Errorf("unhandled frame type: %T", frame)
|
||||
}
|
||||
|
||||
if frameErr != nil {
|
||||
debugMessage("frame handling error: %s", frameErr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Connection) getStreamPriority(streamId spdy.StreamId) uint8 {
|
||||
stream, streamOk := s.getStream(streamId)
|
||||
if !streamOk {
|
||||
return 7
|
||||
}
|
||||
return stream.priority
|
||||
}
|
||||
|
||||
func (s *Connection) addStreamFrame(frame *spdy.SynStreamFrame) {
|
||||
var parent *Stream
|
||||
if frame.AssociatedToStreamId != spdy.StreamId(0) {
|
||||
parent, _ = s.getStream(frame.AssociatedToStreamId)
|
||||
}
|
||||
|
||||
stream := &Stream{
|
||||
streamId: frame.StreamId,
|
||||
parent: parent,
|
||||
conn: s,
|
||||
startChan: make(chan error),
|
||||
headers: frame.Headers,
|
||||
finished: (frame.CFHeader.Flags & spdy.ControlFlagUnidirectional) != 0x00,
|
||||
replyCond: sync.NewCond(new(sync.Mutex)),
|
||||
dataChan: make(chan []byte),
|
||||
headerChan: make(chan http.Header),
|
||||
closeChan: make(chan bool),
|
||||
priority: frame.Priority,
|
||||
}
|
||||
if frame.CFHeader.Flags&spdy.ControlFlagFin != 0x00 {
|
||||
stream.closeRemoteChannels()
|
||||
}
|
||||
|
||||
s.addStream(stream)
|
||||
}
|
||||
|
||||
// checkStreamFrame checks to see if a stream frame is allowed.
|
||||
// If the stream is invalid, then a reset frame with protocol error
|
||||
// will be returned.
|
||||
func (s *Connection) checkStreamFrame(frame *spdy.SynStreamFrame) bool {
|
||||
s.receiveIdLock.Lock()
|
||||
defer s.receiveIdLock.Unlock()
|
||||
if s.goneAway {
|
||||
return false
|
||||
}
|
||||
validationErr := s.validateStreamId(frame.StreamId)
|
||||
if validationErr != nil {
|
||||
go func() {
|
||||
resetErr := s.sendResetFrame(spdy.ProtocolError, frame.StreamId)
|
||||
if resetErr != nil {
|
||||
debugMessage("reset error: %s", resetErr)
|
||||
}
|
||||
}()
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *Connection) handleStreamFrame(frame *spdy.SynStreamFrame, newHandler StreamHandler) error {
|
||||
stream, ok := s.getStream(frame.StreamId)
|
||||
if !ok {
|
||||
return fmt.Errorf("Missing stream: %d", frame.StreamId)
|
||||
}
|
||||
|
||||
newHandler(stream)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Connection) handleReplyFrame(frame *spdy.SynReplyFrame) error {
|
||||
debugMessage("(%p) Reply frame received for %d", s, frame.StreamId)
|
||||
stream, streamOk := s.getStream(frame.StreamId)
|
||||
if !streamOk {
|
||||
debugMessage("Reply frame gone away for %d", frame.StreamId)
|
||||
// Stream has already gone away
|
||||
return nil
|
||||
}
|
||||
if stream.replied {
|
||||
// Stream has already received reply
|
||||
return nil
|
||||
}
|
||||
stream.replied = true
|
||||
|
||||
// TODO Check for error
|
||||
if (frame.CFHeader.Flags & spdy.ControlFlagFin) != 0x00 {
|
||||
s.remoteStreamFinish(stream)
|
||||
}
|
||||
|
||||
close(stream.startChan)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Connection) handleResetFrame(frame *spdy.RstStreamFrame) error {
|
||||
stream, streamOk := s.getStream(frame.StreamId)
|
||||
if !streamOk {
|
||||
// Stream has already been removed
|
||||
return nil
|
||||
}
|
||||
s.removeStream(stream)
|
||||
stream.closeRemoteChannels()
|
||||
|
||||
if !stream.replied {
|
||||
stream.replied = true
|
||||
stream.startChan <- ErrReset
|
||||
close(stream.startChan)
|
||||
}
|
||||
|
||||
stream.finishLock.Lock()
|
||||
stream.finished = true
|
||||
stream.finishLock.Unlock()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Connection) handleHeaderFrame(frame *spdy.HeadersFrame) error {
|
||||
stream, streamOk := s.getStream(frame.StreamId)
|
||||
if !streamOk {
|
||||
// Stream has already gone away
|
||||
return nil
|
||||
}
|
||||
if !stream.replied {
|
||||
// No reply received...Protocol error?
|
||||
return nil
|
||||
}
|
||||
|
||||
// TODO limit headers while not blocking (use buffered chan or goroutine?)
|
||||
select {
|
||||
case <-stream.closeChan:
|
||||
return nil
|
||||
case stream.headerChan <- frame.Headers:
|
||||
}
|
||||
|
||||
if (frame.CFHeader.Flags & spdy.ControlFlagFin) != 0x00 {
|
||||
s.remoteStreamFinish(stream)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Connection) handleDataFrame(frame *spdy.DataFrame) error {
|
||||
debugMessage("(%p) Data frame received for %d", s, frame.StreamId)
|
||||
stream, streamOk := s.getStream(frame.StreamId)
|
||||
if !streamOk {
|
||||
debugMessage("(%p) Data frame gone away for %d", s, frame.StreamId)
|
||||
// Stream has already gone away
|
||||
return nil
|
||||
}
|
||||
if !stream.replied {
|
||||
debugMessage("(%p) Data frame not replied %d", s, frame.StreamId)
|
||||
// No reply received...Protocol error?
|
||||
return nil
|
||||
}
|
||||
|
||||
debugMessage("(%p) (%d) Data frame handling", stream, stream.streamId)
|
||||
if len(frame.Data) > 0 {
|
||||
stream.dataLock.RLock()
|
||||
select {
|
||||
case <-stream.closeChan:
|
||||
debugMessage("(%p) (%d) Data frame not sent (stream shut down)", stream, stream.streamId)
|
||||
case stream.dataChan <- frame.Data:
|
||||
debugMessage("(%p) (%d) Data frame sent", stream, stream.streamId)
|
||||
}
|
||||
stream.dataLock.RUnlock()
|
||||
}
|
||||
if (frame.Flags & spdy.DataFlagFin) != 0x00 {
|
||||
s.remoteStreamFinish(stream)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Connection) handlePingFrame(frame *spdy.PingFrame) error {
|
||||
if s.pingId&0x01 != frame.Id&0x01 {
|
||||
return s.framer.WriteFrame(frame)
|
||||
}
|
||||
pingChan, pingOk := s.pingChans[frame.Id]
|
||||
if pingOk {
|
||||
close(pingChan)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Connection) handleGoAwayFrame(frame *spdy.GoAwayFrame) error {
|
||||
debugMessage("(%p) Go away received", s)
|
||||
s.receiveIdLock.Lock()
|
||||
if s.goneAway {
|
||||
s.receiveIdLock.Unlock()
|
||||
return nil
|
||||
}
|
||||
s.goneAway = true
|
||||
s.receiveIdLock.Unlock()
|
||||
|
||||
if s.lastStreamChan != nil {
|
||||
stream, _ := s.getStream(frame.LastGoodStreamId)
|
||||
go func() {
|
||||
s.lastStreamChan <- stream
|
||||
}()
|
||||
}
|
||||
|
||||
// Do not block frame handler waiting for closure
|
||||
go s.shutdown(s.goAwayTimeout)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Connection) remoteStreamFinish(stream *Stream) {
|
||||
stream.closeRemoteChannels()
|
||||
|
||||
stream.finishLock.Lock()
|
||||
if stream.finished {
|
||||
// Stream is fully closed, cleanup
|
||||
s.removeStream(stream)
|
||||
}
|
||||
stream.finishLock.Unlock()
|
||||
}
|
||||
|
||||
// CreateStream creates a new spdy stream using the parameters for
|
||||
// creating the stream frame. The stream frame will be sent upon
|
||||
// calling this function, however this function does not wait for
|
||||
// the reply frame. If waiting for the reply is desired, use
|
||||
// the stream Wait or WaitTimeout function on the stream returned
|
||||
// by this function.
|
||||
func (s *Connection) CreateStream(headers http.Header, parent *Stream, fin bool) (*Stream, error) {
|
||||
// MUST synchronize stream creation (all the way to writing the frame)
|
||||
// as stream IDs **MUST** increase monotonically.
|
||||
s.nextIdLock.Lock()
|
||||
defer s.nextIdLock.Unlock()
|
||||
|
||||
streamId := s.getNextStreamId()
|
||||
if streamId == 0 {
|
||||
return nil, fmt.Errorf("Unable to get new stream id")
|
||||
}
|
||||
|
||||
stream := &Stream{
|
||||
streamId: streamId,
|
||||
parent: parent,
|
||||
conn: s,
|
||||
startChan: make(chan error),
|
||||
headers: headers,
|
||||
dataChan: make(chan []byte),
|
||||
headerChan: make(chan http.Header),
|
||||
closeChan: make(chan bool),
|
||||
}
|
||||
|
||||
debugMessage("(%p) (%p) Create stream", s, stream)
|
||||
|
||||
s.addStream(stream)
|
||||
|
||||
return stream, s.sendStream(stream, fin)
|
||||
}
|
||||
|
||||
func (s *Connection) shutdown(closeTimeout time.Duration) {
|
||||
// TODO Ensure this isn't called multiple times
|
||||
s.shutdownLock.Lock()
|
||||
if s.hasShutdown {
|
||||
s.shutdownLock.Unlock()
|
||||
return
|
||||
}
|
||||
s.hasShutdown = true
|
||||
s.shutdownLock.Unlock()
|
||||
|
||||
var timeout <-chan time.Time
|
||||
if closeTimeout > time.Duration(0) {
|
||||
timeout = time.After(closeTimeout)
|
||||
}
|
||||
streamsClosed := make(chan bool)
|
||||
|
||||
go func() {
|
||||
s.streamCond.L.Lock()
|
||||
for len(s.streams) > 0 {
|
||||
debugMessage("Streams opened: %d, %#v", len(s.streams), s.streams)
|
||||
s.streamCond.Wait()
|
||||
}
|
||||
s.streamCond.L.Unlock()
|
||||
close(streamsClosed)
|
||||
}()
|
||||
|
||||
var err error
|
||||
select {
|
||||
case <-streamsClosed:
|
||||
// No active streams, close should be safe
|
||||
err = s.conn.Close()
|
||||
case <-timeout:
|
||||
// Force ungraceful close
|
||||
err = s.conn.Close()
|
||||
// Wait for cleanup to clear active streams
|
||||
<-streamsClosed
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
duration := 10 * time.Minute
|
||||
time.AfterFunc(duration, func() {
|
||||
select {
|
||||
case err, ok := <-s.shutdownChan:
|
||||
if ok {
|
||||
debugMessage("Unhandled close error after %s: %s", duration, err)
|
||||
}
|
||||
default:
|
||||
}
|
||||
})
|
||||
s.shutdownChan <- err
|
||||
}
|
||||
close(s.shutdownChan)
|
||||
}
|
||||
|
||||
// Closes spdy connection by sending GoAway frame and initiating shutdown
|
||||
func (s *Connection) Close() error {
|
||||
s.receiveIdLock.Lock()
|
||||
if s.goneAway {
|
||||
s.receiveIdLock.Unlock()
|
||||
return nil
|
||||
}
|
||||
s.goneAway = true
|
||||
s.receiveIdLock.Unlock()
|
||||
|
||||
var lastStreamId spdy.StreamId
|
||||
if s.receivedStreamId > 2 {
|
||||
lastStreamId = s.receivedStreamId - 2
|
||||
}
|
||||
|
||||
goAwayFrame := &spdy.GoAwayFrame{
|
||||
LastGoodStreamId: lastStreamId,
|
||||
Status: spdy.GoAwayOK,
|
||||
}
|
||||
|
||||
err := s.framer.WriteFrame(goAwayFrame)
|
||||
go s.shutdown(s.closeTimeout)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CloseWait closes the connection and waits for shutdown
|
||||
// to finish. Note the underlying network Connection
|
||||
// is not closed until the end of shutdown.
|
||||
func (s *Connection) CloseWait() error {
|
||||
closeErr := s.Close()
|
||||
if closeErr != nil {
|
||||
return closeErr
|
||||
}
|
||||
shutdownErr, ok := <-s.shutdownChan
|
||||
if ok {
|
||||
return shutdownErr
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Wait waits for the connection to finish shutdown or for
|
||||
// the wait timeout duration to expire. This needs to be
|
||||
// called either after Close has been called or the GOAWAYFRAME
|
||||
// has been received. If the wait timeout is 0, this function
|
||||
// will block until shutdown finishes. If wait is never called
|
||||
// and a shutdown error occurs, that error will be logged as an
|
||||
// unhandled error.
|
||||
func (s *Connection) Wait(waitTimeout time.Duration) error {
|
||||
var timeout <-chan time.Time
|
||||
if waitTimeout > time.Duration(0) {
|
||||
timeout = time.After(waitTimeout)
|
||||
}
|
||||
|
||||
select {
|
||||
case err, ok := <-s.shutdownChan:
|
||||
if ok {
|
||||
return err
|
||||
}
|
||||
case <-timeout:
|
||||
return ErrTimeout
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NotifyClose registers a channel to be called when the remote
|
||||
// peer inidicates connection closure. The last stream to be
|
||||
// received by the remote will be sent on the channel. The notify
|
||||
// timeout will determine the duration between go away received
|
||||
// and the connection being closed.
|
||||
func (s *Connection) NotifyClose(c chan<- *Stream, timeout time.Duration) {
|
||||
s.goAwayTimeout = timeout
|
||||
s.lastStreamChan = c
|
||||
}
|
||||
|
||||
// SetCloseTimeout sets the amount of time close will wait for
|
||||
// streams to finish before terminating the underlying network
|
||||
// connection. Setting the timeout to 0 will cause close to
|
||||
// wait forever, which is the default.
|
||||
func (s *Connection) SetCloseTimeout(timeout time.Duration) {
|
||||
s.closeTimeout = timeout
|
||||
}
|
||||
|
||||
// SetIdleTimeout sets the amount of time the connection may sit idle before
|
||||
// it is forcefully terminated.
|
||||
func (s *Connection) SetIdleTimeout(timeout time.Duration) {
|
||||
s.framer.setIdleTimeout(timeout)
|
||||
}
|
||||
|
||||
func (s *Connection) sendHeaders(headers http.Header, stream *Stream, fin bool) error {
|
||||
var flags spdy.ControlFlags
|
||||
if fin {
|
||||
flags = spdy.ControlFlagFin
|
||||
}
|
||||
|
||||
headerFrame := &spdy.HeadersFrame{
|
||||
StreamId: stream.streamId,
|
||||
Headers: headers,
|
||||
CFHeader: spdy.ControlFrameHeader{Flags: flags},
|
||||
}
|
||||
|
||||
return s.framer.WriteFrame(headerFrame)
|
||||
}
|
||||
|
||||
func (s *Connection) sendReply(headers http.Header, stream *Stream, fin bool) error {
|
||||
var flags spdy.ControlFlags
|
||||
if fin {
|
||||
flags = spdy.ControlFlagFin
|
||||
}
|
||||
|
||||
replyFrame := &spdy.SynReplyFrame{
|
||||
StreamId: stream.streamId,
|
||||
Headers: headers,
|
||||
CFHeader: spdy.ControlFrameHeader{Flags: flags},
|
||||
}
|
||||
|
||||
return s.framer.WriteFrame(replyFrame)
|
||||
}
|
||||
|
||||
func (s *Connection) sendResetFrame(status spdy.RstStreamStatus, streamId spdy.StreamId) error {
|
||||
resetFrame := &spdy.RstStreamFrame{
|
||||
StreamId: streamId,
|
||||
Status: status,
|
||||
}
|
||||
|
||||
return s.framer.WriteFrame(resetFrame)
|
||||
}
|
||||
|
||||
func (s *Connection) sendReset(status spdy.RstStreamStatus, stream *Stream) error {
|
||||
return s.sendResetFrame(status, stream.streamId)
|
||||
}
|
||||
|
||||
func (s *Connection) sendStream(stream *Stream, fin bool) error {
|
||||
var flags spdy.ControlFlags
|
||||
if fin {
|
||||
flags = spdy.ControlFlagFin
|
||||
stream.finished = true
|
||||
}
|
||||
|
||||
var parentId spdy.StreamId
|
||||
if stream.parent != nil {
|
||||
parentId = stream.parent.streamId
|
||||
}
|
||||
|
||||
streamFrame := &spdy.SynStreamFrame{
|
||||
StreamId: spdy.StreamId(stream.streamId),
|
||||
AssociatedToStreamId: spdy.StreamId(parentId),
|
||||
Headers: stream.headers,
|
||||
CFHeader: spdy.ControlFrameHeader{Flags: flags},
|
||||
}
|
||||
|
||||
return s.framer.WriteFrame(streamFrame)
|
||||
}
|
||||
|
||||
// getNextStreamId returns the next sequential id
|
||||
// every call should produce a unique value or an error
|
||||
func (s *Connection) getNextStreamId() spdy.StreamId {
|
||||
sid := s.nextStreamId
|
||||
if sid > 0x7fffffff {
|
||||
return 0
|
||||
}
|
||||
s.nextStreamId = s.nextStreamId + 2
|
||||
return sid
|
||||
}
|
||||
|
||||
// PeekNextStreamId returns the next sequential id and keeps the next id untouched
|
||||
func (s *Connection) PeekNextStreamId() spdy.StreamId {
|
||||
sid := s.nextStreamId
|
||||
return sid
|
||||
}
|
||||
|
||||
func (s *Connection) validateStreamId(rid spdy.StreamId) error {
|
||||
if rid > 0x7fffffff || rid < s.receivedStreamId {
|
||||
return ErrInvalidStreamId
|
||||
}
|
||||
s.receivedStreamId = rid + 2
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Connection) addStream(stream *Stream) {
|
||||
s.streamCond.L.Lock()
|
||||
s.streams[stream.streamId] = stream
|
||||
debugMessage("(%p) (%p) Stream added, broadcasting: %d", s, stream, stream.streamId)
|
||||
s.streamCond.Broadcast()
|
||||
s.streamCond.L.Unlock()
|
||||
}
|
||||
|
||||
func (s *Connection) removeStream(stream *Stream) {
|
||||
s.streamCond.L.Lock()
|
||||
delete(s.streams, stream.streamId)
|
||||
debugMessage("(%p) (%p) Stream removed, broadcasting: %d", s, stream, stream.streamId)
|
||||
s.streamCond.Broadcast()
|
||||
s.streamCond.L.Unlock()
|
||||
}
|
||||
|
||||
func (s *Connection) getStream(streamId spdy.StreamId) (stream *Stream, ok bool) {
|
||||
s.streamLock.RLock()
|
||||
stream, ok = s.streams[streamId]
|
||||
s.streamLock.RUnlock()
|
||||
return
|
||||
}
|
||||
|
||||
// FindStream looks up the given stream id and either waits for the
|
||||
// stream to be found or returns nil if the stream id is no longer
|
||||
// valid.
|
||||
func (s *Connection) FindStream(streamId uint32) *Stream {
|
||||
var stream *Stream
|
||||
var ok bool
|
||||
s.streamCond.L.Lock()
|
||||
stream, ok = s.streams[spdy.StreamId(streamId)]
|
||||
debugMessage("(%p) Found stream %d? %t", s, spdy.StreamId(streamId), ok)
|
||||
for !ok && streamId >= uint32(s.receivedStreamId) {
|
||||
s.streamCond.Wait()
|
||||
stream, ok = s.streams[spdy.StreamId(streamId)]
|
||||
}
|
||||
s.streamCond.L.Unlock()
|
||||
return stream
|
||||
}
|
||||
|
||||
func (s *Connection) CloseChan() <-chan bool {
|
||||
return s.closeChan
|
||||
}
|
||||
52
vendor/github.com/moby/spdystream/handlers.go
generated
vendored
Normal file
52
vendor/github.com/moby/spdystream/handlers.go
generated
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
Copyright 2014-2021 Docker Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package spdystream
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// MirrorStreamHandler mirrors all streams.
|
||||
func MirrorStreamHandler(stream *Stream) {
|
||||
replyErr := stream.SendReply(http.Header{}, false)
|
||||
if replyErr != nil {
|
||||
return
|
||||
}
|
||||
|
||||
go func() {
|
||||
io.Copy(stream, stream)
|
||||
stream.Close()
|
||||
}()
|
||||
go func() {
|
||||
for {
|
||||
header, receiveErr := stream.ReceiveHeader()
|
||||
if receiveErr != nil {
|
||||
return
|
||||
}
|
||||
sendErr := stream.SendHeader(header, false)
|
||||
if sendErr != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// NoopStreamHandler does nothing when stream connects.
|
||||
func NoOpStreamHandler(stream *Stream) {
|
||||
stream.SendReply(http.Header{}, false)
|
||||
}
|
||||
114
vendor/github.com/moby/spdystream/priority.go
generated
vendored
Normal file
114
vendor/github.com/moby/spdystream/priority.go
generated
vendored
Normal file
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
Copyright 2014-2021 Docker Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package spdystream
|
||||
|
||||
import (
|
||||
"container/heap"
|
||||
"sync"
|
||||
|
||||
"github.com/moby/spdystream/spdy"
|
||||
)
|
||||
|
||||
type prioritizedFrame struct {
|
||||
frame spdy.Frame
|
||||
priority uint8
|
||||
insertId uint64
|
||||
}
|
||||
|
||||
type frameQueue []*prioritizedFrame
|
||||
|
||||
func (fq frameQueue) Len() int {
|
||||
return len(fq)
|
||||
}
|
||||
|
||||
func (fq frameQueue) Less(i, j int) bool {
|
||||
if fq[i].priority == fq[j].priority {
|
||||
return fq[i].insertId < fq[j].insertId
|
||||
}
|
||||
return fq[i].priority < fq[j].priority
|
||||
}
|
||||
|
||||
func (fq frameQueue) Swap(i, j int) {
|
||||
fq[i], fq[j] = fq[j], fq[i]
|
||||
}
|
||||
|
||||
func (fq *frameQueue) Push(x interface{}) {
|
||||
*fq = append(*fq, x.(*prioritizedFrame))
|
||||
}
|
||||
|
||||
func (fq *frameQueue) Pop() interface{} {
|
||||
old := *fq
|
||||
n := len(old)
|
||||
*fq = old[0 : n-1]
|
||||
return old[n-1]
|
||||
}
|
||||
|
||||
type PriorityFrameQueue struct {
|
||||
queue *frameQueue
|
||||
c *sync.Cond
|
||||
size int
|
||||
nextInsertId uint64
|
||||
drain bool
|
||||
}
|
||||
|
||||
func NewPriorityFrameQueue(size int) *PriorityFrameQueue {
|
||||
queue := make(frameQueue, 0, size)
|
||||
heap.Init(&queue)
|
||||
|
||||
return &PriorityFrameQueue{
|
||||
queue: &queue,
|
||||
size: size,
|
||||
c: sync.NewCond(&sync.Mutex{}),
|
||||
}
|
||||
}
|
||||
|
||||
func (q *PriorityFrameQueue) Push(frame spdy.Frame, priority uint8) {
|
||||
q.c.L.Lock()
|
||||
defer q.c.L.Unlock()
|
||||
for q.queue.Len() >= q.size {
|
||||
q.c.Wait()
|
||||
}
|
||||
pFrame := &prioritizedFrame{
|
||||
frame: frame,
|
||||
priority: priority,
|
||||
insertId: q.nextInsertId,
|
||||
}
|
||||
q.nextInsertId = q.nextInsertId + 1
|
||||
heap.Push(q.queue, pFrame)
|
||||
q.c.Signal()
|
||||
}
|
||||
|
||||
func (q *PriorityFrameQueue) Pop() spdy.Frame {
|
||||
q.c.L.Lock()
|
||||
defer q.c.L.Unlock()
|
||||
for q.queue.Len() == 0 {
|
||||
if q.drain {
|
||||
return nil
|
||||
}
|
||||
q.c.Wait()
|
||||
}
|
||||
frame := heap.Pop(q.queue).(*prioritizedFrame).frame
|
||||
q.c.Signal()
|
||||
return frame
|
||||
}
|
||||
|
||||
func (q *PriorityFrameQueue) Drain() {
|
||||
q.c.L.Lock()
|
||||
defer q.c.L.Unlock()
|
||||
q.drain = true
|
||||
q.c.Broadcast()
|
||||
}
|
||||
203
vendor/github.com/moby/spdystream/spdy/dictionary.go
generated
vendored
Normal file
203
vendor/github.com/moby/spdystream/spdy/dictionary.go
generated
vendored
Normal file
@@ -0,0 +1,203 @@
|
||||
/*
|
||||
Copyright 2014-2021 Docker Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// 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.
|
||||
|
||||
package spdy
|
||||
|
||||
// headerDictionary is the dictionary sent to the zlib compressor/decompressor.
|
||||
var headerDictionary = []byte{
|
||||
0x00, 0x00, 0x00, 0x07, 0x6f, 0x70, 0x74, 0x69,
|
||||
0x6f, 0x6e, 0x73, 0x00, 0x00, 0x00, 0x04, 0x68,
|
||||
0x65, 0x61, 0x64, 0x00, 0x00, 0x00, 0x04, 0x70,
|
||||
0x6f, 0x73, 0x74, 0x00, 0x00, 0x00, 0x03, 0x70,
|
||||
0x75, 0x74, 0x00, 0x00, 0x00, 0x06, 0x64, 0x65,
|
||||
0x6c, 0x65, 0x74, 0x65, 0x00, 0x00, 0x00, 0x05,
|
||||
0x74, 0x72, 0x61, 0x63, 0x65, 0x00, 0x00, 0x00,
|
||||
0x06, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x00,
|
||||
0x00, 0x00, 0x0e, 0x61, 0x63, 0x63, 0x65, 0x70,
|
||||
0x74, 0x2d, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65,
|
||||
0x74, 0x00, 0x00, 0x00, 0x0f, 0x61, 0x63, 0x63,
|
||||
0x65, 0x70, 0x74, 0x2d, 0x65, 0x6e, 0x63, 0x6f,
|
||||
0x64, 0x69, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x0f,
|
||||
0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x6c,
|
||||
0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x00,
|
||||
0x00, 0x00, 0x0d, 0x61, 0x63, 0x63, 0x65, 0x70,
|
||||
0x74, 0x2d, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x73,
|
||||
0x00, 0x00, 0x00, 0x03, 0x61, 0x67, 0x65, 0x00,
|
||||
0x00, 0x00, 0x05, 0x61, 0x6c, 0x6c, 0x6f, 0x77,
|
||||
0x00, 0x00, 0x00, 0x0d, 0x61, 0x75, 0x74, 0x68,
|
||||
0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f,
|
||||
0x6e, 0x00, 0x00, 0x00, 0x0d, 0x63, 0x61, 0x63,
|
||||
0x68, 0x65, 0x2d, 0x63, 0x6f, 0x6e, 0x74, 0x72,
|
||||
0x6f, 0x6c, 0x00, 0x00, 0x00, 0x0a, 0x63, 0x6f,
|
||||
0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e,
|
||||
0x00, 0x00, 0x00, 0x0c, 0x63, 0x6f, 0x6e, 0x74,
|
||||
0x65, 0x6e, 0x74, 0x2d, 0x62, 0x61, 0x73, 0x65,
|
||||
0x00, 0x00, 0x00, 0x10, 0x63, 0x6f, 0x6e, 0x74,
|
||||
0x65, 0x6e, 0x74, 0x2d, 0x65, 0x6e, 0x63, 0x6f,
|
||||
0x64, 0x69, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x10,
|
||||
0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d,
|
||||
0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65,
|
||||
0x00, 0x00, 0x00, 0x0e, 0x63, 0x6f, 0x6e, 0x74,
|
||||
0x65, 0x6e, 0x74, 0x2d, 0x6c, 0x65, 0x6e, 0x67,
|
||||
0x74, 0x68, 0x00, 0x00, 0x00, 0x10, 0x63, 0x6f,
|
||||
0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x6c, 0x6f,
|
||||
0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00,
|
||||
0x00, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e,
|
||||
0x74, 0x2d, 0x6d, 0x64, 0x35, 0x00, 0x00, 0x00,
|
||||
0x0d, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74,
|
||||
0x2d, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x00, 0x00,
|
||||
0x00, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e,
|
||||
0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x00, 0x00,
|
||||
0x00, 0x04, 0x64, 0x61, 0x74, 0x65, 0x00, 0x00,
|
||||
0x00, 0x04, 0x65, 0x74, 0x61, 0x67, 0x00, 0x00,
|
||||
0x00, 0x06, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74,
|
||||
0x00, 0x00, 0x00, 0x07, 0x65, 0x78, 0x70, 0x69,
|
||||
0x72, 0x65, 0x73, 0x00, 0x00, 0x00, 0x04, 0x66,
|
||||
0x72, 0x6f, 0x6d, 0x00, 0x00, 0x00, 0x04, 0x68,
|
||||
0x6f, 0x73, 0x74, 0x00, 0x00, 0x00, 0x08, 0x69,
|
||||
0x66, 0x2d, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x00,
|
||||
0x00, 0x00, 0x11, 0x69, 0x66, 0x2d, 0x6d, 0x6f,
|
||||
0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x2d, 0x73,
|
||||
0x69, 0x6e, 0x63, 0x65, 0x00, 0x00, 0x00, 0x0d,
|
||||
0x69, 0x66, 0x2d, 0x6e, 0x6f, 0x6e, 0x65, 0x2d,
|
||||
0x6d, 0x61, 0x74, 0x63, 0x68, 0x00, 0x00, 0x00,
|
||||
0x08, 0x69, 0x66, 0x2d, 0x72, 0x61, 0x6e, 0x67,
|
||||
0x65, 0x00, 0x00, 0x00, 0x13, 0x69, 0x66, 0x2d,
|
||||
0x75, 0x6e, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69,
|
||||
0x65, 0x64, 0x2d, 0x73, 0x69, 0x6e, 0x63, 0x65,
|
||||
0x00, 0x00, 0x00, 0x0d, 0x6c, 0x61, 0x73, 0x74,
|
||||
0x2d, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65,
|
||||
0x64, 0x00, 0x00, 0x00, 0x08, 0x6c, 0x6f, 0x63,
|
||||
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00,
|
||||
0x0c, 0x6d, 0x61, 0x78, 0x2d, 0x66, 0x6f, 0x72,
|
||||
0x77, 0x61, 0x72, 0x64, 0x73, 0x00, 0x00, 0x00,
|
||||
0x06, 0x70, 0x72, 0x61, 0x67, 0x6d, 0x61, 0x00,
|
||||
0x00, 0x00, 0x12, 0x70, 0x72, 0x6f, 0x78, 0x79,
|
||||
0x2d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74,
|
||||
0x69, 0x63, 0x61, 0x74, 0x65, 0x00, 0x00, 0x00,
|
||||
0x13, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2d, 0x61,
|
||||
0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61,
|
||||
0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, 0x05,
|
||||
0x72, 0x61, 0x6e, 0x67, 0x65, 0x00, 0x00, 0x00,
|
||||
0x07, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x72,
|
||||
0x00, 0x00, 0x00, 0x0b, 0x72, 0x65, 0x74, 0x72,
|
||||
0x79, 0x2d, 0x61, 0x66, 0x74, 0x65, 0x72, 0x00,
|
||||
0x00, 0x00, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65,
|
||||
0x72, 0x00, 0x00, 0x00, 0x02, 0x74, 0x65, 0x00,
|
||||
0x00, 0x00, 0x07, 0x74, 0x72, 0x61, 0x69, 0x6c,
|
||||
0x65, 0x72, 0x00, 0x00, 0x00, 0x11, 0x74, 0x72,
|
||||
0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x2d, 0x65,
|
||||
0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x00,
|
||||
0x00, 0x00, 0x07, 0x75, 0x70, 0x67, 0x72, 0x61,
|
||||
0x64, 0x65, 0x00, 0x00, 0x00, 0x0a, 0x75, 0x73,
|
||||
0x65, 0x72, 0x2d, 0x61, 0x67, 0x65, 0x6e, 0x74,
|
||||
0x00, 0x00, 0x00, 0x04, 0x76, 0x61, 0x72, 0x79,
|
||||
0x00, 0x00, 0x00, 0x03, 0x76, 0x69, 0x61, 0x00,
|
||||
0x00, 0x00, 0x07, 0x77, 0x61, 0x72, 0x6e, 0x69,
|
||||
0x6e, 0x67, 0x00, 0x00, 0x00, 0x10, 0x77, 0x77,
|
||||
0x77, 0x2d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e,
|
||||
0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x00, 0x00,
|
||||
0x00, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64,
|
||||
0x00, 0x00, 0x00, 0x03, 0x67, 0x65, 0x74, 0x00,
|
||||
0x00, 0x00, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75,
|
||||
0x73, 0x00, 0x00, 0x00, 0x06, 0x32, 0x30, 0x30,
|
||||
0x20, 0x4f, 0x4b, 0x00, 0x00, 0x00, 0x07, 0x76,
|
||||
0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x00, 0x00,
|
||||
0x00, 0x08, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31,
|
||||
0x2e, 0x31, 0x00, 0x00, 0x00, 0x03, 0x75, 0x72,
|
||||
0x6c, 0x00, 0x00, 0x00, 0x06, 0x70, 0x75, 0x62,
|
||||
0x6c, 0x69, 0x63, 0x00, 0x00, 0x00, 0x0a, 0x73,
|
||||
0x65, 0x74, 0x2d, 0x63, 0x6f, 0x6f, 0x6b, 0x69,
|
||||
0x65, 0x00, 0x00, 0x00, 0x0a, 0x6b, 0x65, 0x65,
|
||||
0x70, 0x2d, 0x61, 0x6c, 0x69, 0x76, 0x65, 0x00,
|
||||
0x00, 0x00, 0x06, 0x6f, 0x72, 0x69, 0x67, 0x69,
|
||||
0x6e, 0x31, 0x30, 0x30, 0x31, 0x30, 0x31, 0x32,
|
||||
0x30, 0x31, 0x32, 0x30, 0x32, 0x32, 0x30, 0x35,
|
||||
0x32, 0x30, 0x36, 0x33, 0x30, 0x30, 0x33, 0x30,
|
||||
0x32, 0x33, 0x30, 0x33, 0x33, 0x30, 0x34, 0x33,
|
||||
0x30, 0x35, 0x33, 0x30, 0x36, 0x33, 0x30, 0x37,
|
||||
0x34, 0x30, 0x32, 0x34, 0x30, 0x35, 0x34, 0x30,
|
||||
0x36, 0x34, 0x30, 0x37, 0x34, 0x30, 0x38, 0x34,
|
||||
0x30, 0x39, 0x34, 0x31, 0x30, 0x34, 0x31, 0x31,
|
||||
0x34, 0x31, 0x32, 0x34, 0x31, 0x33, 0x34, 0x31,
|
||||
0x34, 0x34, 0x31, 0x35, 0x34, 0x31, 0x36, 0x34,
|
||||
0x31, 0x37, 0x35, 0x30, 0x32, 0x35, 0x30, 0x34,
|
||||
0x35, 0x30, 0x35, 0x32, 0x30, 0x33, 0x20, 0x4e,
|
||||
0x6f, 0x6e, 0x2d, 0x41, 0x75, 0x74, 0x68, 0x6f,
|
||||
0x72, 0x69, 0x74, 0x61, 0x74, 0x69, 0x76, 0x65,
|
||||
0x20, 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61,
|
||||
0x74, 0x69, 0x6f, 0x6e, 0x32, 0x30, 0x34, 0x20,
|
||||
0x4e, 0x6f, 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x65,
|
||||
0x6e, 0x74, 0x33, 0x30, 0x31, 0x20, 0x4d, 0x6f,
|
||||
0x76, 0x65, 0x64, 0x20, 0x50, 0x65, 0x72, 0x6d,
|
||||
0x61, 0x6e, 0x65, 0x6e, 0x74, 0x6c, 0x79, 0x34,
|
||||
0x30, 0x30, 0x20, 0x42, 0x61, 0x64, 0x20, 0x52,
|
||||
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x34, 0x30,
|
||||
0x31, 0x20, 0x55, 0x6e, 0x61, 0x75, 0x74, 0x68,
|
||||
0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x34, 0x30,
|
||||
0x33, 0x20, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64,
|
||||
0x64, 0x65, 0x6e, 0x34, 0x30, 0x34, 0x20, 0x4e,
|
||||
0x6f, 0x74, 0x20, 0x46, 0x6f, 0x75, 0x6e, 0x64,
|
||||
0x35, 0x30, 0x30, 0x20, 0x49, 0x6e, 0x74, 0x65,
|
||||
0x72, 0x6e, 0x61, 0x6c, 0x20, 0x53, 0x65, 0x72,
|
||||
0x76, 0x65, 0x72, 0x20, 0x45, 0x72, 0x72, 0x6f,
|
||||
0x72, 0x35, 0x30, 0x31, 0x20, 0x4e, 0x6f, 0x74,
|
||||
0x20, 0x49, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65,
|
||||
0x6e, 0x74, 0x65, 0x64, 0x35, 0x30, 0x33, 0x20,
|
||||
0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x20,
|
||||
0x55, 0x6e, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61,
|
||||
0x62, 0x6c, 0x65, 0x4a, 0x61, 0x6e, 0x20, 0x46,
|
||||
0x65, 0x62, 0x20, 0x4d, 0x61, 0x72, 0x20, 0x41,
|
||||
0x70, 0x72, 0x20, 0x4d, 0x61, 0x79, 0x20, 0x4a,
|
||||
0x75, 0x6e, 0x20, 0x4a, 0x75, 0x6c, 0x20, 0x41,
|
||||
0x75, 0x67, 0x20, 0x53, 0x65, 0x70, 0x74, 0x20,
|
||||
0x4f, 0x63, 0x74, 0x20, 0x4e, 0x6f, 0x76, 0x20,
|
||||
0x44, 0x65, 0x63, 0x20, 0x30, 0x30, 0x3a, 0x30,
|
||||
0x30, 0x3a, 0x30, 0x30, 0x20, 0x4d, 0x6f, 0x6e,
|
||||
0x2c, 0x20, 0x54, 0x75, 0x65, 0x2c, 0x20, 0x57,
|
||||
0x65, 0x64, 0x2c, 0x20, 0x54, 0x68, 0x75, 0x2c,
|
||||
0x20, 0x46, 0x72, 0x69, 0x2c, 0x20, 0x53, 0x61,
|
||||
0x74, 0x2c, 0x20, 0x53, 0x75, 0x6e, 0x2c, 0x20,
|
||||
0x47, 0x4d, 0x54, 0x63, 0x68, 0x75, 0x6e, 0x6b,
|
||||
0x65, 0x64, 0x2c, 0x74, 0x65, 0x78, 0x74, 0x2f,
|
||||
0x68, 0x74, 0x6d, 0x6c, 0x2c, 0x69, 0x6d, 0x61,
|
||||
0x67, 0x65, 0x2f, 0x70, 0x6e, 0x67, 0x2c, 0x69,
|
||||
0x6d, 0x61, 0x67, 0x65, 0x2f, 0x6a, 0x70, 0x67,
|
||||
0x2c, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x67,
|
||||
0x69, 0x66, 0x2c, 0x61, 0x70, 0x70, 0x6c, 0x69,
|
||||
0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78,
|
||||
0x6d, 0x6c, 0x2c, 0x61, 0x70, 0x70, 0x6c, 0x69,
|
||||
0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78,
|
||||
0x68, 0x74, 0x6d, 0x6c, 0x2b, 0x78, 0x6d, 0x6c,
|
||||
0x2c, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x70, 0x6c,
|
||||
0x61, 0x69, 0x6e, 0x2c, 0x74, 0x65, 0x78, 0x74,
|
||||
0x2f, 0x6a, 0x61, 0x76, 0x61, 0x73, 0x63, 0x72,
|
||||
0x69, 0x70, 0x74, 0x2c, 0x70, 0x75, 0x62, 0x6c,
|
||||
0x69, 0x63, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74,
|
||||
0x65, 0x6d, 0x61, 0x78, 0x2d, 0x61, 0x67, 0x65,
|
||||
0x3d, 0x67, 0x7a, 0x69, 0x70, 0x2c, 0x64, 0x65,
|
||||
0x66, 0x6c, 0x61, 0x74, 0x65, 0x2c, 0x73, 0x64,
|
||||
0x63, 0x68, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65,
|
||||
0x74, 0x3d, 0x75, 0x74, 0x66, 0x2d, 0x38, 0x63,
|
||||
0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x3d, 0x69,
|
||||
0x73, 0x6f, 0x2d, 0x38, 0x38, 0x35, 0x39, 0x2d,
|
||||
0x31, 0x2c, 0x75, 0x74, 0x66, 0x2d, 0x2c, 0x2a,
|
||||
0x2c, 0x65, 0x6e, 0x71, 0x3d, 0x30, 0x2e,
|
||||
}
|
||||
364
vendor/github.com/moby/spdystream/spdy/read.go
generated
vendored
Normal file
364
vendor/github.com/moby/spdystream/spdy/read.go
generated
vendored
Normal file
@@ -0,0 +1,364 @@
|
||||
/*
|
||||
Copyright 2014-2021 Docker Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// 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.
|
||||
|
||||
package spdy
|
||||
|
||||
import (
|
||||
"compress/zlib"
|
||||
"encoding/binary"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func (frame *SynStreamFrame) read(h ControlFrameHeader, f *Framer) error {
|
||||
return f.readSynStreamFrame(h, frame)
|
||||
}
|
||||
|
||||
func (frame *SynReplyFrame) read(h ControlFrameHeader, f *Framer) error {
|
||||
return f.readSynReplyFrame(h, frame)
|
||||
}
|
||||
|
||||
func (frame *RstStreamFrame) read(h ControlFrameHeader, f *Framer) error {
|
||||
frame.CFHeader = h
|
||||
if err := binary.Read(f.r, binary.BigEndian, &frame.StreamId); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Read(f.r, binary.BigEndian, &frame.Status); err != nil {
|
||||
return err
|
||||
}
|
||||
if frame.Status == 0 {
|
||||
return &Error{InvalidControlFrame, frame.StreamId}
|
||||
}
|
||||
if frame.StreamId == 0 {
|
||||
return &Error{ZeroStreamId, 0}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (frame *SettingsFrame) read(h ControlFrameHeader, f *Framer) error {
|
||||
frame.CFHeader = h
|
||||
var numSettings uint32
|
||||
if err := binary.Read(f.r, binary.BigEndian, &numSettings); err != nil {
|
||||
return err
|
||||
}
|
||||
frame.FlagIdValues = make([]SettingsFlagIdValue, numSettings)
|
||||
for i := uint32(0); i < numSettings; i++ {
|
||||
if err := binary.Read(f.r, binary.BigEndian, &frame.FlagIdValues[i].Id); err != nil {
|
||||
return err
|
||||
}
|
||||
frame.FlagIdValues[i].Flag = SettingsFlag((frame.FlagIdValues[i].Id & 0xff000000) >> 24)
|
||||
frame.FlagIdValues[i].Id &= 0xffffff
|
||||
if err := binary.Read(f.r, binary.BigEndian, &frame.FlagIdValues[i].Value); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (frame *PingFrame) read(h ControlFrameHeader, f *Framer) error {
|
||||
frame.CFHeader = h
|
||||
if err := binary.Read(f.r, binary.BigEndian, &frame.Id); err != nil {
|
||||
return err
|
||||
}
|
||||
if frame.Id == 0 {
|
||||
return &Error{ZeroStreamId, 0}
|
||||
}
|
||||
if frame.CFHeader.Flags != 0 {
|
||||
return &Error{InvalidControlFrame, StreamId(frame.Id)}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (frame *GoAwayFrame) read(h ControlFrameHeader, f *Framer) error {
|
||||
frame.CFHeader = h
|
||||
if err := binary.Read(f.r, binary.BigEndian, &frame.LastGoodStreamId); err != nil {
|
||||
return err
|
||||
}
|
||||
if frame.CFHeader.Flags != 0 {
|
||||
return &Error{InvalidControlFrame, frame.LastGoodStreamId}
|
||||
}
|
||||
if frame.CFHeader.length != 8 {
|
||||
return &Error{InvalidControlFrame, frame.LastGoodStreamId}
|
||||
}
|
||||
if err := binary.Read(f.r, binary.BigEndian, &frame.Status); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (frame *HeadersFrame) read(h ControlFrameHeader, f *Framer) error {
|
||||
return f.readHeadersFrame(h, frame)
|
||||
}
|
||||
|
||||
func (frame *WindowUpdateFrame) read(h ControlFrameHeader, f *Framer) error {
|
||||
frame.CFHeader = h
|
||||
if err := binary.Read(f.r, binary.BigEndian, &frame.StreamId); err != nil {
|
||||
return err
|
||||
}
|
||||
if frame.CFHeader.Flags != 0 {
|
||||
return &Error{InvalidControlFrame, frame.StreamId}
|
||||
}
|
||||
if frame.CFHeader.length != 8 {
|
||||
return &Error{InvalidControlFrame, frame.StreamId}
|
||||
}
|
||||
if err := binary.Read(f.r, binary.BigEndian, &frame.DeltaWindowSize); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func newControlFrame(frameType ControlFrameType) (controlFrame, error) {
|
||||
ctor, ok := cframeCtor[frameType]
|
||||
if !ok {
|
||||
return nil, &Error{Err: InvalidControlFrame}
|
||||
}
|
||||
return ctor(), nil
|
||||
}
|
||||
|
||||
var cframeCtor = map[ControlFrameType]func() controlFrame{
|
||||
TypeSynStream: func() controlFrame { return new(SynStreamFrame) },
|
||||
TypeSynReply: func() controlFrame { return new(SynReplyFrame) },
|
||||
TypeRstStream: func() controlFrame { return new(RstStreamFrame) },
|
||||
TypeSettings: func() controlFrame { return new(SettingsFrame) },
|
||||
TypePing: func() controlFrame { return new(PingFrame) },
|
||||
TypeGoAway: func() controlFrame { return new(GoAwayFrame) },
|
||||
TypeHeaders: func() controlFrame { return new(HeadersFrame) },
|
||||
TypeWindowUpdate: func() controlFrame { return new(WindowUpdateFrame) },
|
||||
}
|
||||
|
||||
func (f *Framer) uncorkHeaderDecompressor(payloadSize int64) error {
|
||||
if f.headerDecompressor != nil {
|
||||
f.headerReader.N = payloadSize
|
||||
return nil
|
||||
}
|
||||
f.headerReader = io.LimitedReader{R: f.r, N: payloadSize}
|
||||
decompressor, err := zlib.NewReaderDict(&f.headerReader, []byte(headerDictionary))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
f.headerDecompressor = decompressor
|
||||
return nil
|
||||
}
|
||||
|
||||
// ReadFrame reads SPDY encoded data and returns a decompressed Frame.
|
||||
func (f *Framer) ReadFrame() (Frame, error) {
|
||||
var firstWord uint32
|
||||
if err := binary.Read(f.r, binary.BigEndian, &firstWord); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if firstWord&0x80000000 != 0 {
|
||||
frameType := ControlFrameType(firstWord & 0xffff)
|
||||
version := uint16(firstWord >> 16 & 0x7fff)
|
||||
return f.parseControlFrame(version, frameType)
|
||||
}
|
||||
return f.parseDataFrame(StreamId(firstWord & 0x7fffffff))
|
||||
}
|
||||
|
||||
func (f *Framer) parseControlFrame(version uint16, frameType ControlFrameType) (Frame, error) {
|
||||
var length uint32
|
||||
if err := binary.Read(f.r, binary.BigEndian, &length); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
flags := ControlFlags((length & 0xff000000) >> 24)
|
||||
length &= 0xffffff
|
||||
header := ControlFrameHeader{version, frameType, flags, length}
|
||||
cframe, err := newControlFrame(frameType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = cframe.read(header, f); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return cframe, nil
|
||||
}
|
||||
|
||||
func parseHeaderValueBlock(r io.Reader, streamId StreamId) (http.Header, error) {
|
||||
var numHeaders uint32
|
||||
if err := binary.Read(r, binary.BigEndian, &numHeaders); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var e error
|
||||
h := make(http.Header, int(numHeaders))
|
||||
for i := 0; i < int(numHeaders); i++ {
|
||||
var length uint32
|
||||
if err := binary.Read(r, binary.BigEndian, &length); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nameBytes := make([]byte, length)
|
||||
if _, err := io.ReadFull(r, nameBytes); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
name := string(nameBytes)
|
||||
if name != strings.ToLower(name) {
|
||||
e = &Error{UnlowercasedHeaderName, streamId}
|
||||
name = strings.ToLower(name)
|
||||
}
|
||||
if h[name] != nil {
|
||||
e = &Error{DuplicateHeaders, streamId}
|
||||
}
|
||||
if err := binary.Read(r, binary.BigEndian, &length); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
value := make([]byte, length)
|
||||
if _, err := io.ReadFull(r, value); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
valueList := strings.Split(string(value), headerValueSeparator)
|
||||
for _, v := range valueList {
|
||||
h.Add(name, v)
|
||||
}
|
||||
}
|
||||
if e != nil {
|
||||
return h, e
|
||||
}
|
||||
return h, nil
|
||||
}
|
||||
|
||||
func (f *Framer) readSynStreamFrame(h ControlFrameHeader, frame *SynStreamFrame) error {
|
||||
frame.CFHeader = h
|
||||
var err error
|
||||
if err = binary.Read(f.r, binary.BigEndian, &frame.StreamId); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = binary.Read(f.r, binary.BigEndian, &frame.AssociatedToStreamId); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = binary.Read(f.r, binary.BigEndian, &frame.Priority); err != nil {
|
||||
return err
|
||||
}
|
||||
frame.Priority >>= 5
|
||||
if err = binary.Read(f.r, binary.BigEndian, &frame.Slot); err != nil {
|
||||
return err
|
||||
}
|
||||
reader := f.r
|
||||
if !f.headerCompressionDisabled {
|
||||
err := f.uncorkHeaderDecompressor(int64(h.length - 10))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
reader = f.headerDecompressor
|
||||
}
|
||||
frame.Headers, err = parseHeaderValueBlock(reader, frame.StreamId)
|
||||
if !f.headerCompressionDisabled && (err == io.EOF && f.headerReader.N == 0 || f.headerReader.N != 0) {
|
||||
err = &Error{WrongCompressedPayloadSize, 0}
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for h := range frame.Headers {
|
||||
if invalidReqHeaders[h] {
|
||||
return &Error{InvalidHeaderPresent, frame.StreamId}
|
||||
}
|
||||
}
|
||||
if frame.StreamId == 0 {
|
||||
return &Error{ZeroStreamId, 0}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *Framer) readSynReplyFrame(h ControlFrameHeader, frame *SynReplyFrame) error {
|
||||
frame.CFHeader = h
|
||||
var err error
|
||||
if err = binary.Read(f.r, binary.BigEndian, &frame.StreamId); err != nil {
|
||||
return err
|
||||
}
|
||||
reader := f.r
|
||||
if !f.headerCompressionDisabled {
|
||||
err := f.uncorkHeaderDecompressor(int64(h.length - 4))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
reader = f.headerDecompressor
|
||||
}
|
||||
frame.Headers, err = parseHeaderValueBlock(reader, frame.StreamId)
|
||||
if !f.headerCompressionDisabled && (err == io.EOF && f.headerReader.N == 0 || f.headerReader.N != 0) {
|
||||
err = &Error{WrongCompressedPayloadSize, 0}
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for h := range frame.Headers {
|
||||
if invalidRespHeaders[h] {
|
||||
return &Error{InvalidHeaderPresent, frame.StreamId}
|
||||
}
|
||||
}
|
||||
if frame.StreamId == 0 {
|
||||
return &Error{ZeroStreamId, 0}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *Framer) readHeadersFrame(h ControlFrameHeader, frame *HeadersFrame) error {
|
||||
frame.CFHeader = h
|
||||
var err error
|
||||
if err = binary.Read(f.r, binary.BigEndian, &frame.StreamId); err != nil {
|
||||
return err
|
||||
}
|
||||
reader := f.r
|
||||
if !f.headerCompressionDisabled {
|
||||
err := f.uncorkHeaderDecompressor(int64(h.length - 4))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
reader = f.headerDecompressor
|
||||
}
|
||||
frame.Headers, err = parseHeaderValueBlock(reader, frame.StreamId)
|
||||
if !f.headerCompressionDisabled && (err == io.EOF && f.headerReader.N == 0 || f.headerReader.N != 0) {
|
||||
err = &Error{WrongCompressedPayloadSize, 0}
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var invalidHeaders map[string]bool
|
||||
if frame.StreamId%2 == 0 {
|
||||
invalidHeaders = invalidReqHeaders
|
||||
} else {
|
||||
invalidHeaders = invalidRespHeaders
|
||||
}
|
||||
for h := range frame.Headers {
|
||||
if invalidHeaders[h] {
|
||||
return &Error{InvalidHeaderPresent, frame.StreamId}
|
||||
}
|
||||
}
|
||||
if frame.StreamId == 0 {
|
||||
return &Error{ZeroStreamId, 0}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *Framer) parseDataFrame(streamId StreamId) (*DataFrame, error) {
|
||||
var length uint32
|
||||
if err := binary.Read(f.r, binary.BigEndian, &length); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var frame DataFrame
|
||||
frame.StreamId = streamId
|
||||
frame.Flags = DataFlags(length >> 24)
|
||||
length &= 0xffffff
|
||||
frame.Data = make([]byte, length)
|
||||
if _, err := io.ReadFull(f.r, frame.Data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if frame.StreamId == 0 {
|
||||
return nil, &Error{ZeroStreamId, 0}
|
||||
}
|
||||
return &frame, nil
|
||||
}
|
||||
291
vendor/github.com/moby/spdystream/spdy/types.go
generated
vendored
Normal file
291
vendor/github.com/moby/spdystream/spdy/types.go
generated
vendored
Normal file
@@ -0,0 +1,291 @@
|
||||
/*
|
||||
Copyright 2014-2021 Docker Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// 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.
|
||||
|
||||
// Package spdy implements the SPDY protocol (currently SPDY/3), described in
|
||||
// http://www.chromium.org/spdy/spdy-protocol/spdy-protocol-draft3.
|
||||
package spdy
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/zlib"
|
||||
"io"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// Version is the protocol version number that this package implements.
|
||||
const Version = 3
|
||||
|
||||
// ControlFrameType stores the type field in a control frame header.
|
||||
type ControlFrameType uint16
|
||||
|
||||
const (
|
||||
TypeSynStream ControlFrameType = 0x0001
|
||||
TypeSynReply ControlFrameType = 0x0002
|
||||
TypeRstStream ControlFrameType = 0x0003
|
||||
TypeSettings ControlFrameType = 0x0004
|
||||
TypePing ControlFrameType = 0x0006
|
||||
TypeGoAway ControlFrameType = 0x0007
|
||||
TypeHeaders ControlFrameType = 0x0008
|
||||
TypeWindowUpdate ControlFrameType = 0x0009
|
||||
)
|
||||
|
||||
// ControlFlags are the flags that can be set on a control frame.
|
||||
type ControlFlags uint8
|
||||
|
||||
const (
|
||||
ControlFlagFin ControlFlags = 0x01
|
||||
ControlFlagUnidirectional ControlFlags = 0x02
|
||||
ControlFlagSettingsClearSettings ControlFlags = 0x01
|
||||
)
|
||||
|
||||
// DataFlags are the flags that can be set on a data frame.
|
||||
type DataFlags uint8
|
||||
|
||||
const (
|
||||
DataFlagFin DataFlags = 0x01
|
||||
)
|
||||
|
||||
// MaxDataLength is the maximum number of bytes that can be stored in one frame.
|
||||
const MaxDataLength = 1<<24 - 1
|
||||
|
||||
// headerValueSepator separates multiple header values.
|
||||
const headerValueSeparator = "\x00"
|
||||
|
||||
// Frame is a single SPDY frame in its unpacked in-memory representation. Use
|
||||
// Framer to read and write it.
|
||||
type Frame interface {
|
||||
write(f *Framer) error
|
||||
}
|
||||
|
||||
// ControlFrameHeader contains all the fields in a control frame header,
|
||||
// in its unpacked in-memory representation.
|
||||
type ControlFrameHeader struct {
|
||||
// Note, high bit is the "Control" bit.
|
||||
version uint16 // spdy version number
|
||||
frameType ControlFrameType
|
||||
Flags ControlFlags
|
||||
length uint32 // length of data field
|
||||
}
|
||||
|
||||
type controlFrame interface {
|
||||
Frame
|
||||
read(h ControlFrameHeader, f *Framer) error
|
||||
}
|
||||
|
||||
// StreamId represents a 31-bit value identifying the stream.
|
||||
type StreamId uint32
|
||||
|
||||
// SynStreamFrame is the unpacked, in-memory representation of a SYN_STREAM
|
||||
// frame.
|
||||
type SynStreamFrame struct {
|
||||
CFHeader ControlFrameHeader
|
||||
StreamId StreamId
|
||||
AssociatedToStreamId StreamId // stream id for a stream which this stream is associated to
|
||||
Priority uint8 // priority of this frame (3-bit)
|
||||
Slot uint8 // index in the server's credential vector of the client certificate
|
||||
Headers http.Header
|
||||
}
|
||||
|
||||
// SynReplyFrame is the unpacked, in-memory representation of a SYN_REPLY frame.
|
||||
type SynReplyFrame struct {
|
||||
CFHeader ControlFrameHeader
|
||||
StreamId StreamId
|
||||
Headers http.Header
|
||||
}
|
||||
|
||||
// RstStreamStatus represents the status that led to a RST_STREAM.
|
||||
type RstStreamStatus uint32
|
||||
|
||||
const (
|
||||
ProtocolError RstStreamStatus = iota + 1
|
||||
InvalidStream
|
||||
RefusedStream
|
||||
UnsupportedVersion
|
||||
Cancel
|
||||
InternalError
|
||||
FlowControlError
|
||||
StreamInUse
|
||||
StreamAlreadyClosed
|
||||
InvalidCredentials
|
||||
FrameTooLarge
|
||||
)
|
||||
|
||||
// RstStreamFrame is the unpacked, in-memory representation of a RST_STREAM
|
||||
// frame.
|
||||
type RstStreamFrame struct {
|
||||
CFHeader ControlFrameHeader
|
||||
StreamId StreamId
|
||||
Status RstStreamStatus
|
||||
}
|
||||
|
||||
// SettingsFlag represents a flag in a SETTINGS frame.
|
||||
type SettingsFlag uint8
|
||||
|
||||
const (
|
||||
FlagSettingsPersistValue SettingsFlag = 0x1
|
||||
FlagSettingsPersisted SettingsFlag = 0x2
|
||||
)
|
||||
|
||||
// SettingsFlag represents the id of an id/value pair in a SETTINGS frame.
|
||||
type SettingsId uint32
|
||||
|
||||
const (
|
||||
SettingsUploadBandwidth SettingsId = iota + 1
|
||||
SettingsDownloadBandwidth
|
||||
SettingsRoundTripTime
|
||||
SettingsMaxConcurrentStreams
|
||||
SettingsCurrentCwnd
|
||||
SettingsDownloadRetransRate
|
||||
SettingsInitialWindowSize
|
||||
SettingsClientCretificateVectorSize
|
||||
)
|
||||
|
||||
// SettingsFlagIdValue is the unpacked, in-memory representation of the
|
||||
// combined flag/id/value for a setting in a SETTINGS frame.
|
||||
type SettingsFlagIdValue struct {
|
||||
Flag SettingsFlag
|
||||
Id SettingsId
|
||||
Value uint32
|
||||
}
|
||||
|
||||
// SettingsFrame is the unpacked, in-memory representation of a SPDY
|
||||
// SETTINGS frame.
|
||||
type SettingsFrame struct {
|
||||
CFHeader ControlFrameHeader
|
||||
FlagIdValues []SettingsFlagIdValue
|
||||
}
|
||||
|
||||
// PingFrame is the unpacked, in-memory representation of a PING frame.
|
||||
type PingFrame struct {
|
||||
CFHeader ControlFrameHeader
|
||||
Id uint32 // unique id for this ping, from server is even, from client is odd.
|
||||
}
|
||||
|
||||
// GoAwayStatus represents the status in a GoAwayFrame.
|
||||
type GoAwayStatus uint32
|
||||
|
||||
const (
|
||||
GoAwayOK GoAwayStatus = iota
|
||||
GoAwayProtocolError
|
||||
GoAwayInternalError
|
||||
)
|
||||
|
||||
// GoAwayFrame is the unpacked, in-memory representation of a GOAWAY frame.
|
||||
type GoAwayFrame struct {
|
||||
CFHeader ControlFrameHeader
|
||||
LastGoodStreamId StreamId // last stream id which was accepted by sender
|
||||
Status GoAwayStatus
|
||||
}
|
||||
|
||||
// HeadersFrame is the unpacked, in-memory representation of a HEADERS frame.
|
||||
type HeadersFrame struct {
|
||||
CFHeader ControlFrameHeader
|
||||
StreamId StreamId
|
||||
Headers http.Header
|
||||
}
|
||||
|
||||
// WindowUpdateFrame is the unpacked, in-memory representation of a
|
||||
// WINDOW_UPDATE frame.
|
||||
type WindowUpdateFrame struct {
|
||||
CFHeader ControlFrameHeader
|
||||
StreamId StreamId
|
||||
DeltaWindowSize uint32 // additional number of bytes to existing window size
|
||||
}
|
||||
|
||||
// TODO: Implement credential frame and related methods.
|
||||
|
||||
// DataFrame is the unpacked, in-memory representation of a DATA frame.
|
||||
type DataFrame struct {
|
||||
// Note, high bit is the "Control" bit. Should be 0 for data frames.
|
||||
StreamId StreamId
|
||||
Flags DataFlags
|
||||
Data []byte // payload data of this frame
|
||||
}
|
||||
|
||||
// A SPDY specific error.
|
||||
type ErrorCode string
|
||||
|
||||
const (
|
||||
UnlowercasedHeaderName ErrorCode = "header was not lowercased"
|
||||
DuplicateHeaders ErrorCode = "multiple headers with same name"
|
||||
WrongCompressedPayloadSize ErrorCode = "compressed payload size was incorrect"
|
||||
UnknownFrameType ErrorCode = "unknown frame type"
|
||||
InvalidControlFrame ErrorCode = "invalid control frame"
|
||||
InvalidDataFrame ErrorCode = "invalid data frame"
|
||||
InvalidHeaderPresent ErrorCode = "frame contained invalid header"
|
||||
ZeroStreamId ErrorCode = "stream id zero is disallowed"
|
||||
)
|
||||
|
||||
// Error contains both the type of error and additional values. StreamId is 0
|
||||
// if Error is not associated with a stream.
|
||||
type Error struct {
|
||||
Err ErrorCode
|
||||
StreamId StreamId
|
||||
}
|
||||
|
||||
func (e *Error) Error() string {
|
||||
return string(e.Err)
|
||||
}
|
||||
|
||||
var invalidReqHeaders = map[string]bool{
|
||||
"Connection": true,
|
||||
"Host": true,
|
||||
"Keep-Alive": true,
|
||||
"Proxy-Connection": true,
|
||||
"Transfer-Encoding": true,
|
||||
}
|
||||
|
||||
var invalidRespHeaders = map[string]bool{
|
||||
"Connection": true,
|
||||
"Keep-Alive": true,
|
||||
"Proxy-Connection": true,
|
||||
"Transfer-Encoding": true,
|
||||
}
|
||||
|
||||
// Framer handles serializing/deserializing SPDY frames, including compressing/
|
||||
// decompressing payloads.
|
||||
type Framer struct {
|
||||
headerCompressionDisabled bool
|
||||
w io.Writer
|
||||
headerBuf *bytes.Buffer
|
||||
headerCompressor *zlib.Writer
|
||||
r io.Reader
|
||||
headerReader io.LimitedReader
|
||||
headerDecompressor io.ReadCloser
|
||||
}
|
||||
|
||||
// NewFramer allocates a new Framer for a given SPDY connection, represented by
|
||||
// a io.Writer and io.Reader. Note that Framer will read and write individual fields
|
||||
// from/to the Reader and Writer, so the caller should pass in an appropriately
|
||||
// buffered implementation to optimize performance.
|
||||
func NewFramer(w io.Writer, r io.Reader) (*Framer, error) {
|
||||
compressBuf := new(bytes.Buffer)
|
||||
compressor, err := zlib.NewWriterLevelDict(compressBuf, zlib.BestCompression, []byte(headerDictionary))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
framer := &Framer{
|
||||
w: w,
|
||||
headerBuf: compressBuf,
|
||||
headerCompressor: compressor,
|
||||
r: r,
|
||||
}
|
||||
return framer, nil
|
||||
}
|
||||
334
vendor/github.com/moby/spdystream/spdy/write.go
generated
vendored
Normal file
334
vendor/github.com/moby/spdystream/spdy/write.go
generated
vendored
Normal file
@@ -0,0 +1,334 @@
|
||||
/*
|
||||
Copyright 2014-2021 Docker Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// 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.
|
||||
|
||||
package spdy
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func (frame *SynStreamFrame) write(f *Framer) error {
|
||||
return f.writeSynStreamFrame(frame)
|
||||
}
|
||||
|
||||
func (frame *SynReplyFrame) write(f *Framer) error {
|
||||
return f.writeSynReplyFrame(frame)
|
||||
}
|
||||
|
||||
func (frame *RstStreamFrame) write(f *Framer) (err error) {
|
||||
if frame.StreamId == 0 {
|
||||
return &Error{ZeroStreamId, 0}
|
||||
}
|
||||
frame.CFHeader.version = Version
|
||||
frame.CFHeader.frameType = TypeRstStream
|
||||
frame.CFHeader.Flags = 0
|
||||
frame.CFHeader.length = 8
|
||||
|
||||
// Serialize frame to Writer.
|
||||
if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
|
||||
return
|
||||
}
|
||||
if err = binary.Write(f.w, binary.BigEndian, frame.StreamId); err != nil {
|
||||
return
|
||||
}
|
||||
if frame.Status == 0 {
|
||||
return &Error{InvalidControlFrame, frame.StreamId}
|
||||
}
|
||||
if err = binary.Write(f.w, binary.BigEndian, frame.Status); err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (frame *SettingsFrame) write(f *Framer) (err error) {
|
||||
frame.CFHeader.version = Version
|
||||
frame.CFHeader.frameType = TypeSettings
|
||||
frame.CFHeader.length = uint32(len(frame.FlagIdValues)*8 + 4)
|
||||
|
||||
// Serialize frame to Writer.
|
||||
if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
|
||||
return
|
||||
}
|
||||
if err = binary.Write(f.w, binary.BigEndian, uint32(len(frame.FlagIdValues))); err != nil {
|
||||
return
|
||||
}
|
||||
for _, flagIdValue := range frame.FlagIdValues {
|
||||
flagId := uint32(flagIdValue.Flag)<<24 | uint32(flagIdValue.Id)
|
||||
if err = binary.Write(f.w, binary.BigEndian, flagId); err != nil {
|
||||
return
|
||||
}
|
||||
if err = binary.Write(f.w, binary.BigEndian, flagIdValue.Value); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (frame *PingFrame) write(f *Framer) (err error) {
|
||||
if frame.Id == 0 {
|
||||
return &Error{ZeroStreamId, 0}
|
||||
}
|
||||
frame.CFHeader.version = Version
|
||||
frame.CFHeader.frameType = TypePing
|
||||
frame.CFHeader.Flags = 0
|
||||
frame.CFHeader.length = 4
|
||||
|
||||
// Serialize frame to Writer.
|
||||
if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
|
||||
return
|
||||
}
|
||||
if err = binary.Write(f.w, binary.BigEndian, frame.Id); err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (frame *GoAwayFrame) write(f *Framer) (err error) {
|
||||
frame.CFHeader.version = Version
|
||||
frame.CFHeader.frameType = TypeGoAway
|
||||
frame.CFHeader.Flags = 0
|
||||
frame.CFHeader.length = 8
|
||||
|
||||
// Serialize frame to Writer.
|
||||
if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
|
||||
return
|
||||
}
|
||||
if err = binary.Write(f.w, binary.BigEndian, frame.LastGoodStreamId); err != nil {
|
||||
return
|
||||
}
|
||||
if err = binary.Write(f.w, binary.BigEndian, frame.Status); err != nil {
|
||||
return
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (frame *HeadersFrame) write(f *Framer) error {
|
||||
return f.writeHeadersFrame(frame)
|
||||
}
|
||||
|
||||
func (frame *WindowUpdateFrame) write(f *Framer) (err error) {
|
||||
frame.CFHeader.version = Version
|
||||
frame.CFHeader.frameType = TypeWindowUpdate
|
||||
frame.CFHeader.Flags = 0
|
||||
frame.CFHeader.length = 8
|
||||
|
||||
// Serialize frame to Writer.
|
||||
if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
|
||||
return
|
||||
}
|
||||
if err = binary.Write(f.w, binary.BigEndian, frame.StreamId); err != nil {
|
||||
return
|
||||
}
|
||||
if err = binary.Write(f.w, binary.BigEndian, frame.DeltaWindowSize); err != nil {
|
||||
return
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (frame *DataFrame) write(f *Framer) error {
|
||||
return f.writeDataFrame(frame)
|
||||
}
|
||||
|
||||
// WriteFrame writes a frame.
|
||||
func (f *Framer) WriteFrame(frame Frame) error {
|
||||
return frame.write(f)
|
||||
}
|
||||
|
||||
func writeControlFrameHeader(w io.Writer, h ControlFrameHeader) error {
|
||||
if err := binary.Write(w, binary.BigEndian, 0x8000|h.version); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := binary.Write(w, binary.BigEndian, h.frameType); err != nil {
|
||||
return err
|
||||
}
|
||||
flagsAndLength := uint32(h.Flags)<<24 | h.length
|
||||
if err := binary.Write(w, binary.BigEndian, flagsAndLength); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func writeHeaderValueBlock(w io.Writer, h http.Header) (n int, err error) {
|
||||
n = 0
|
||||
if err = binary.Write(w, binary.BigEndian, uint32(len(h))); err != nil {
|
||||
return
|
||||
}
|
||||
n += 2
|
||||
for name, values := range h {
|
||||
if err = binary.Write(w, binary.BigEndian, uint32(len(name))); err != nil {
|
||||
return
|
||||
}
|
||||
n += 2
|
||||
name = strings.ToLower(name)
|
||||
if _, err = io.WriteString(w, name); err != nil {
|
||||
return
|
||||
}
|
||||
n += len(name)
|
||||
v := strings.Join(values, headerValueSeparator)
|
||||
if err = binary.Write(w, binary.BigEndian, uint32(len(v))); err != nil {
|
||||
return
|
||||
}
|
||||
n += 2
|
||||
if _, err = io.WriteString(w, v); err != nil {
|
||||
return
|
||||
}
|
||||
n += len(v)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (f *Framer) writeSynStreamFrame(frame *SynStreamFrame) (err error) {
|
||||
if frame.StreamId == 0 {
|
||||
return &Error{ZeroStreamId, 0}
|
||||
}
|
||||
// Marshal the headers.
|
||||
var writer io.Writer = f.headerBuf
|
||||
if !f.headerCompressionDisabled {
|
||||
writer = f.headerCompressor
|
||||
}
|
||||
if _, err = writeHeaderValueBlock(writer, frame.Headers); err != nil {
|
||||
return
|
||||
}
|
||||
if !f.headerCompressionDisabled {
|
||||
f.headerCompressor.Flush()
|
||||
}
|
||||
|
||||
// Set ControlFrameHeader.
|
||||
frame.CFHeader.version = Version
|
||||
frame.CFHeader.frameType = TypeSynStream
|
||||
frame.CFHeader.length = uint32(len(f.headerBuf.Bytes()) + 10)
|
||||
|
||||
// Serialize frame to Writer.
|
||||
if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = binary.Write(f.w, binary.BigEndian, frame.StreamId); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = binary.Write(f.w, binary.BigEndian, frame.AssociatedToStreamId); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = binary.Write(f.w, binary.BigEndian, frame.Priority<<5); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = binary.Write(f.w, binary.BigEndian, frame.Slot); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err = f.w.Write(f.headerBuf.Bytes()); err != nil {
|
||||
return err
|
||||
}
|
||||
f.headerBuf.Reset()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *Framer) writeSynReplyFrame(frame *SynReplyFrame) (err error) {
|
||||
if frame.StreamId == 0 {
|
||||
return &Error{ZeroStreamId, 0}
|
||||
}
|
||||
// Marshal the headers.
|
||||
var writer io.Writer = f.headerBuf
|
||||
if !f.headerCompressionDisabled {
|
||||
writer = f.headerCompressor
|
||||
}
|
||||
if _, err = writeHeaderValueBlock(writer, frame.Headers); err != nil {
|
||||
return
|
||||
}
|
||||
if !f.headerCompressionDisabled {
|
||||
f.headerCompressor.Flush()
|
||||
}
|
||||
|
||||
// Set ControlFrameHeader.
|
||||
frame.CFHeader.version = Version
|
||||
frame.CFHeader.frameType = TypeSynReply
|
||||
frame.CFHeader.length = uint32(len(f.headerBuf.Bytes()) + 4)
|
||||
|
||||
// Serialize frame to Writer.
|
||||
if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
|
||||
return
|
||||
}
|
||||
if err = binary.Write(f.w, binary.BigEndian, frame.StreamId); err != nil {
|
||||
return
|
||||
}
|
||||
if _, err = f.w.Write(f.headerBuf.Bytes()); err != nil {
|
||||
return
|
||||
}
|
||||
f.headerBuf.Reset()
|
||||
return
|
||||
}
|
||||
|
||||
func (f *Framer) writeHeadersFrame(frame *HeadersFrame) (err error) {
|
||||
if frame.StreamId == 0 {
|
||||
return &Error{ZeroStreamId, 0}
|
||||
}
|
||||
// Marshal the headers.
|
||||
var writer io.Writer = f.headerBuf
|
||||
if !f.headerCompressionDisabled {
|
||||
writer = f.headerCompressor
|
||||
}
|
||||
if _, err = writeHeaderValueBlock(writer, frame.Headers); err != nil {
|
||||
return
|
||||
}
|
||||
if !f.headerCompressionDisabled {
|
||||
f.headerCompressor.Flush()
|
||||
}
|
||||
|
||||
// Set ControlFrameHeader.
|
||||
frame.CFHeader.version = Version
|
||||
frame.CFHeader.frameType = TypeHeaders
|
||||
frame.CFHeader.length = uint32(len(f.headerBuf.Bytes()) + 4)
|
||||
|
||||
// Serialize frame to Writer.
|
||||
if err = writeControlFrameHeader(f.w, frame.CFHeader); err != nil {
|
||||
return
|
||||
}
|
||||
if err = binary.Write(f.w, binary.BigEndian, frame.StreamId); err != nil {
|
||||
return
|
||||
}
|
||||
if _, err = f.w.Write(f.headerBuf.Bytes()); err != nil {
|
||||
return
|
||||
}
|
||||
f.headerBuf.Reset()
|
||||
return
|
||||
}
|
||||
|
||||
func (f *Framer) writeDataFrame(frame *DataFrame) (err error) {
|
||||
if frame.StreamId == 0 {
|
||||
return &Error{ZeroStreamId, 0}
|
||||
}
|
||||
if frame.StreamId&0x80000000 != 0 || len(frame.Data) > MaxDataLength {
|
||||
return &Error{InvalidDataFrame, frame.StreamId}
|
||||
}
|
||||
|
||||
// Serialize frame to Writer.
|
||||
if err = binary.Write(f.w, binary.BigEndian, frame.StreamId); err != nil {
|
||||
return
|
||||
}
|
||||
flagsAndLength := uint32(frame.Flags)<<24 | uint32(len(frame.Data))
|
||||
if err = binary.Write(f.w, binary.BigEndian, flagsAndLength); err != nil {
|
||||
return
|
||||
}
|
||||
if _, err = f.w.Write(frame.Data); err != nil {
|
||||
return
|
||||
}
|
||||
return nil
|
||||
}
|
||||
343
vendor/github.com/moby/spdystream/stream.go
generated
vendored
Normal file
343
vendor/github.com/moby/spdystream/stream.go
generated
vendored
Normal file
@@ -0,0 +1,343 @@
|
||||
/*
|
||||
Copyright 2014-2021 Docker Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package spdystream
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/moby/spdystream/spdy"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrUnreadPartialData = errors.New("unread partial data")
|
||||
)
|
||||
|
||||
type Stream struct {
|
||||
streamId spdy.StreamId
|
||||
parent *Stream
|
||||
conn *Connection
|
||||
startChan chan error
|
||||
|
||||
dataLock sync.RWMutex
|
||||
dataChan chan []byte
|
||||
unread []byte
|
||||
|
||||
priority uint8
|
||||
headers http.Header
|
||||
headerChan chan http.Header
|
||||
finishLock sync.Mutex
|
||||
finished bool
|
||||
replyCond *sync.Cond
|
||||
replied bool
|
||||
closeLock sync.Mutex
|
||||
closeChan chan bool
|
||||
}
|
||||
|
||||
// WriteData writes data to stream, sending a dataframe per call
|
||||
func (s *Stream) WriteData(data []byte, fin bool) error {
|
||||
s.waitWriteReply()
|
||||
var flags spdy.DataFlags
|
||||
|
||||
if fin {
|
||||
flags = spdy.DataFlagFin
|
||||
s.finishLock.Lock()
|
||||
if s.finished {
|
||||
s.finishLock.Unlock()
|
||||
return ErrWriteClosedStream
|
||||
}
|
||||
s.finished = true
|
||||
s.finishLock.Unlock()
|
||||
}
|
||||
|
||||
dataFrame := &spdy.DataFrame{
|
||||
StreamId: s.streamId,
|
||||
Flags: flags,
|
||||
Data: data,
|
||||
}
|
||||
|
||||
debugMessage("(%p) (%d) Writing data frame", s, s.streamId)
|
||||
return s.conn.framer.WriteFrame(dataFrame)
|
||||
}
|
||||
|
||||
// Write writes bytes to a stream, calling write data for each call.
|
||||
func (s *Stream) Write(data []byte) (n int, err error) {
|
||||
err = s.WriteData(data, false)
|
||||
if err == nil {
|
||||
n = len(data)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Read reads bytes from a stream, a single read will never get more
|
||||
// than what is sent on a single data frame, but a multiple calls to
|
||||
// read may get data from the same data frame.
|
||||
func (s *Stream) Read(p []byte) (n int, err error) {
|
||||
if s.unread == nil {
|
||||
select {
|
||||
case <-s.closeChan:
|
||||
return 0, io.EOF
|
||||
case read, ok := <-s.dataChan:
|
||||
if !ok {
|
||||
return 0, io.EOF
|
||||
}
|
||||
s.unread = read
|
||||
}
|
||||
}
|
||||
n = copy(p, s.unread)
|
||||
if n < len(s.unread) {
|
||||
s.unread = s.unread[n:]
|
||||
} else {
|
||||
s.unread = nil
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// ReadData reads an entire data frame and returns the byte array
|
||||
// from the data frame. If there is unread data from the result
|
||||
// of a Read call, this function will return an ErrUnreadPartialData.
|
||||
func (s *Stream) ReadData() ([]byte, error) {
|
||||
debugMessage("(%p) Reading data from %d", s, s.streamId)
|
||||
if s.unread != nil {
|
||||
return nil, ErrUnreadPartialData
|
||||
}
|
||||
select {
|
||||
case <-s.closeChan:
|
||||
return nil, io.EOF
|
||||
case read, ok := <-s.dataChan:
|
||||
if !ok {
|
||||
return nil, io.EOF
|
||||
}
|
||||
return read, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Stream) waitWriteReply() {
|
||||
if s.replyCond != nil {
|
||||
s.replyCond.L.Lock()
|
||||
for !s.replied {
|
||||
s.replyCond.Wait()
|
||||
}
|
||||
s.replyCond.L.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
// Wait waits for the stream to receive a reply.
|
||||
func (s *Stream) Wait() error {
|
||||
return s.WaitTimeout(time.Duration(0))
|
||||
}
|
||||
|
||||
// WaitTimeout waits for the stream to receive a reply or for timeout.
|
||||
// When the timeout is reached, ErrTimeout will be returned.
|
||||
func (s *Stream) WaitTimeout(timeout time.Duration) error {
|
||||
var timeoutChan <-chan time.Time
|
||||
if timeout > time.Duration(0) {
|
||||
timeoutChan = time.After(timeout)
|
||||
}
|
||||
|
||||
select {
|
||||
case err := <-s.startChan:
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
break
|
||||
case <-timeoutChan:
|
||||
return ErrTimeout
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Close closes the stream by sending an empty data frame with the
|
||||
// finish flag set, indicating this side is finished with the stream.
|
||||
func (s *Stream) Close() error {
|
||||
select {
|
||||
case <-s.closeChan:
|
||||
// Stream is now fully closed
|
||||
s.conn.removeStream(s)
|
||||
default:
|
||||
break
|
||||
}
|
||||
return s.WriteData([]byte{}, true)
|
||||
}
|
||||
|
||||
// Reset sends a reset frame, putting the stream into the fully closed state.
|
||||
func (s *Stream) Reset() error {
|
||||
s.conn.removeStream(s)
|
||||
return s.resetStream()
|
||||
}
|
||||
|
||||
func (s *Stream) resetStream() error {
|
||||
// Always call closeRemoteChannels, even if s.finished is already true.
|
||||
// This makes it so that stream.Close() followed by stream.Reset() allows
|
||||
// stream.Read() to unblock.
|
||||
s.closeRemoteChannels()
|
||||
|
||||
s.finishLock.Lock()
|
||||
if s.finished {
|
||||
s.finishLock.Unlock()
|
||||
return nil
|
||||
}
|
||||
s.finished = true
|
||||
s.finishLock.Unlock()
|
||||
|
||||
resetFrame := &spdy.RstStreamFrame{
|
||||
StreamId: s.streamId,
|
||||
Status: spdy.Cancel,
|
||||
}
|
||||
return s.conn.framer.WriteFrame(resetFrame)
|
||||
}
|
||||
|
||||
// CreateSubStream creates a stream using the current as the parent
|
||||
func (s *Stream) CreateSubStream(headers http.Header, fin bool) (*Stream, error) {
|
||||
return s.conn.CreateStream(headers, s, fin)
|
||||
}
|
||||
|
||||
// SetPriority sets the stream priority, does not affect the
|
||||
// remote priority of this stream after Open has been called.
|
||||
// Valid values are 0 through 7, 0 being the highest priority
|
||||
// and 7 the lowest.
|
||||
func (s *Stream) SetPriority(priority uint8) {
|
||||
s.priority = priority
|
||||
}
|
||||
|
||||
// SendHeader sends a header frame across the stream
|
||||
func (s *Stream) SendHeader(headers http.Header, fin bool) error {
|
||||
return s.conn.sendHeaders(headers, s, fin)
|
||||
}
|
||||
|
||||
// SendReply sends a reply on a stream, only valid to be called once
|
||||
// when handling a new stream
|
||||
func (s *Stream) SendReply(headers http.Header, fin bool) error {
|
||||
if s.replyCond == nil {
|
||||
return errors.New("cannot reply on initiated stream")
|
||||
}
|
||||
s.replyCond.L.Lock()
|
||||
defer s.replyCond.L.Unlock()
|
||||
if s.replied {
|
||||
return nil
|
||||
}
|
||||
|
||||
err := s.conn.sendReply(headers, s, fin)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s.replied = true
|
||||
s.replyCond.Broadcast()
|
||||
return nil
|
||||
}
|
||||
|
||||
// Refuse sends a reset frame with the status refuse, only
|
||||
// valid to be called once when handling a new stream. This
|
||||
// may be used to indicate that a stream is not allowed
|
||||
// when http status codes are not being used.
|
||||
func (s *Stream) Refuse() error {
|
||||
if s.replied {
|
||||
return nil
|
||||
}
|
||||
s.replied = true
|
||||
return s.conn.sendReset(spdy.RefusedStream, s)
|
||||
}
|
||||
|
||||
// Cancel sends a reset frame with the status canceled. This
|
||||
// can be used at any time by the creator of the Stream to
|
||||
// indicate the stream is no longer needed.
|
||||
func (s *Stream) Cancel() error {
|
||||
return s.conn.sendReset(spdy.Cancel, s)
|
||||
}
|
||||
|
||||
// ReceiveHeader receives a header sent on the other side
|
||||
// of the stream. This function will block until a header
|
||||
// is received or stream is closed.
|
||||
func (s *Stream) ReceiveHeader() (http.Header, error) {
|
||||
select {
|
||||
case <-s.closeChan:
|
||||
break
|
||||
case header, ok := <-s.headerChan:
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("header chan closed")
|
||||
}
|
||||
return header, nil
|
||||
}
|
||||
return nil, fmt.Errorf("stream closed")
|
||||
}
|
||||
|
||||
// Parent returns the parent stream
|
||||
func (s *Stream) Parent() *Stream {
|
||||
return s.parent
|
||||
}
|
||||
|
||||
// Headers returns the headers used to create the stream
|
||||
func (s *Stream) Headers() http.Header {
|
||||
return s.headers
|
||||
}
|
||||
|
||||
// String returns the string version of stream using the
|
||||
// streamId to uniquely identify the stream
|
||||
func (s *Stream) String() string {
|
||||
return fmt.Sprintf("stream:%d", s.streamId)
|
||||
}
|
||||
|
||||
// Identifier returns a 32 bit identifier for the stream
|
||||
func (s *Stream) Identifier() uint32 {
|
||||
return uint32(s.streamId)
|
||||
}
|
||||
|
||||
// IsFinished returns whether the stream has finished
|
||||
// sending data
|
||||
func (s *Stream) IsFinished() bool {
|
||||
return s.finished
|
||||
}
|
||||
|
||||
// Implement net.Conn interface
|
||||
|
||||
func (s *Stream) LocalAddr() net.Addr {
|
||||
return s.conn.conn.LocalAddr()
|
||||
}
|
||||
|
||||
func (s *Stream) RemoteAddr() net.Addr {
|
||||
return s.conn.conn.RemoteAddr()
|
||||
}
|
||||
|
||||
// TODO set per stream values instead of connection-wide
|
||||
|
||||
func (s *Stream) SetDeadline(t time.Time) error {
|
||||
return s.conn.conn.SetDeadline(t)
|
||||
}
|
||||
|
||||
func (s *Stream) SetReadDeadline(t time.Time) error {
|
||||
return s.conn.conn.SetReadDeadline(t)
|
||||
}
|
||||
|
||||
func (s *Stream) SetWriteDeadline(t time.Time) error {
|
||||
return s.conn.conn.SetWriteDeadline(t)
|
||||
}
|
||||
|
||||
func (s *Stream) closeRemoteChannels() {
|
||||
s.closeLock.Lock()
|
||||
defer s.closeLock.Unlock()
|
||||
select {
|
||||
case <-s.closeChan:
|
||||
default:
|
||||
close(s.closeChan)
|
||||
}
|
||||
}
|
||||
32
vendor/github.com/moby/spdystream/utils.go
generated
vendored
Normal file
32
vendor/github.com/moby/spdystream/utils.go
generated
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
Copyright 2014-2021 Docker Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package spdystream
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
)
|
||||
|
||||
var (
|
||||
DEBUG = os.Getenv("DEBUG")
|
||||
)
|
||||
|
||||
func debugMessage(fmt string, args ...interface{}) {
|
||||
if DEBUG != "" {
|
||||
log.Printf(fmt, args...)
|
||||
}
|
||||
}
|
||||
202
vendor/github.com/moby/sys/mountinfo/LICENSE
generated
vendored
Normal file
202
vendor/github.com/moby/sys/mountinfo/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
44
vendor/github.com/moby/sys/mountinfo/doc.go
generated
vendored
Normal file
44
vendor/github.com/moby/sys/mountinfo/doc.go
generated
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
// Package mountinfo provides a set of functions to retrieve information about OS mounts.
|
||||
//
|
||||
// Currently it supports Linux. For historical reasons, there is also some support for FreeBSD and OpenBSD,
|
||||
// and a shallow implementation for Windows, but in general this is Linux-only package, so
|
||||
// the rest of the document only applies to Linux, unless explicitly specified otherwise.
|
||||
//
|
||||
// In Linux, information about mounts seen by the current process is available from
|
||||
// /proc/self/mountinfo. Note that due to mount namespaces, different processes can
|
||||
// see different mounts. A per-process mountinfo table is available from /proc/<PID>/mountinfo,
|
||||
// where <PID> is a numerical process identifier.
|
||||
//
|
||||
// In general, /proc is not a very efficient interface, and mountinfo is not an exception.
|
||||
// For example, there is no way to get information about a specific mount point (i.e. it
|
||||
// is all-or-nothing). This package tries to hide the /proc ineffectiveness by using
|
||||
// parse filters while reading mountinfo. A filter can skip some entries, or stop
|
||||
// processing the rest of the file once the needed information is found.
|
||||
//
|
||||
// For mountinfo filters that accept path as an argument, the path must be absolute,
|
||||
// having all symlinks resolved, and being cleaned (i.e. no extra slashes or dots).
|
||||
// One way to achieve all of the above is to employ filepath.Abs followed by
|
||||
// filepath.EvalSymlinks (the latter calls filepath.Clean on the result so
|
||||
// there is no need to explicitly call filepath.Clean).
|
||||
//
|
||||
// NOTE that in many cases there is no need to consult mountinfo at all. Here are some
|
||||
// of the cases where mountinfo should not be parsed:
|
||||
//
|
||||
// 1. Before performing a mount. Usually, this is not needed, but if required (say to
|
||||
// prevent over-mounts), to check whether a directory is mounted, call os.Lstat
|
||||
// on it and its parent directory, and compare their st.Sys().(*syscall.Stat_t).Dev
|
||||
// fields -- if they differ, then the directory is the mount point. NOTE this does
|
||||
// not work for bind mounts. Optionally, the filesystem type can also be checked
|
||||
// by calling unix.Statfs and checking the Type field (i.e. filesystem type).
|
||||
//
|
||||
// 2. After performing a mount. If there is no error returned, the mount succeeded;
|
||||
// checking the mount table for a new mount is redundant and expensive.
|
||||
//
|
||||
// 3. Before performing an unmount. It is more efficient to do an unmount and ignore
|
||||
// a specific error (EINVAL) which tells the directory is not mounted.
|
||||
//
|
||||
// 4. After performing an unmount. If there is no error returned, the unmount succeeded.
|
||||
//
|
||||
// 5. To find the mount point root of a specific directory. You can perform os.Stat()
|
||||
// on the directory and traverse up until the Dev field of a parent directory differs.
|
||||
package mountinfo
|
||||
101
vendor/github.com/moby/sys/mountinfo/mounted_linux.go
generated
vendored
Normal file
101
vendor/github.com/moby/sys/mountinfo/mounted_linux.go
generated
vendored
Normal file
@@ -0,0 +1,101 @@
|
||||
package mountinfo
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// MountedFast is a method of detecting a mount point without reading
|
||||
// mountinfo from procfs. A caller can only trust the result if no error
|
||||
// and sure == true are returned. Otherwise, other methods (e.g. parsing
|
||||
// /proc/mounts) have to be used. If unsure, use Mounted instead (which
|
||||
// uses MountedFast, but falls back to parsing mountinfo if needed).
|
||||
//
|
||||
// If a non-existent path is specified, an appropriate error is returned.
|
||||
// In case the caller is not interested in this particular error, it should
|
||||
// be handled separately using e.g. errors.Is(err, fs.ErrNotExist).
|
||||
//
|
||||
// This function is only available on Linux. When available (since kernel
|
||||
// v5.6), openat2(2) syscall is used to reliably detect all mounts. Otherwise,
|
||||
// the implementation falls back to using stat(2), which can reliably detect
|
||||
// normal (but not bind) mounts.
|
||||
func MountedFast(path string) (mounted, sure bool, err error) {
|
||||
// Root is always mounted.
|
||||
if path == string(os.PathSeparator) {
|
||||
return true, true, nil
|
||||
}
|
||||
|
||||
path, err = normalizePath(path)
|
||||
if err != nil {
|
||||
return false, false, err
|
||||
}
|
||||
mounted, sure, err = mountedFast(path)
|
||||
return
|
||||
}
|
||||
|
||||
// mountedByOpenat2 is a method of detecting a mount that works for all kinds
|
||||
// of mounts (incl. bind mounts), but requires a recent (v5.6+) linux kernel.
|
||||
func mountedByOpenat2(path string) (bool, error) {
|
||||
dir, last := filepath.Split(path)
|
||||
|
||||
dirfd, err := unix.Openat2(unix.AT_FDCWD, dir, &unix.OpenHow{
|
||||
Flags: unix.O_PATH | unix.O_CLOEXEC,
|
||||
})
|
||||
if err != nil {
|
||||
return false, &os.PathError{Op: "openat2", Path: dir, Err: err}
|
||||
}
|
||||
fd, err := unix.Openat2(dirfd, last, &unix.OpenHow{
|
||||
Flags: unix.O_PATH | unix.O_CLOEXEC | unix.O_NOFOLLOW,
|
||||
Resolve: unix.RESOLVE_NO_XDEV,
|
||||
})
|
||||
_ = unix.Close(dirfd)
|
||||
switch err { //nolint:errorlint // unix errors are bare
|
||||
case nil: // definitely not a mount
|
||||
_ = unix.Close(fd)
|
||||
return false, nil
|
||||
case unix.EXDEV: // definitely a mount
|
||||
return true, nil
|
||||
}
|
||||
// not sure
|
||||
return false, &os.PathError{Op: "openat2", Path: path, Err: err}
|
||||
}
|
||||
|
||||
// mountedFast is similar to MountedFast, except it expects a normalized path.
|
||||
func mountedFast(path string) (mounted, sure bool, err error) {
|
||||
// Root is always mounted.
|
||||
if path == string(os.PathSeparator) {
|
||||
return true, true, nil
|
||||
}
|
||||
|
||||
// Try a fast path, using openat2() with RESOLVE_NO_XDEV.
|
||||
mounted, err = mountedByOpenat2(path)
|
||||
if err == nil {
|
||||
return mounted, true, nil
|
||||
}
|
||||
|
||||
// Another fast path: compare st.st_dev fields.
|
||||
mounted, err = mountedByStat(path)
|
||||
// This does not work for bind mounts, so false negative
|
||||
// is possible, therefore only trust if return is true.
|
||||
if mounted && err == nil {
|
||||
return true, true, nil
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func mounted(path string) (bool, error) {
|
||||
path, err := normalizePath(path)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
mounted, sure, err := mountedFast(path)
|
||||
if sure && err == nil {
|
||||
return mounted, nil
|
||||
}
|
||||
|
||||
// Fallback to parsing mountinfo.
|
||||
return mountedByMountinfo(path)
|
||||
}
|
||||
53
vendor/github.com/moby/sys/mountinfo/mounted_unix.go
generated
vendored
Normal file
53
vendor/github.com/moby/sys/mountinfo/mounted_unix.go
generated
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
//go:build linux || freebsd || openbsd || darwin
|
||||
// +build linux freebsd openbsd darwin
|
||||
|
||||
package mountinfo
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
func mountedByStat(path string) (bool, error) {
|
||||
var st unix.Stat_t
|
||||
|
||||
if err := unix.Lstat(path, &st); err != nil {
|
||||
return false, &os.PathError{Op: "stat", Path: path, Err: err}
|
||||
}
|
||||
dev := st.Dev
|
||||
parent := filepath.Dir(path)
|
||||
if err := unix.Lstat(parent, &st); err != nil {
|
||||
return false, &os.PathError{Op: "stat", Path: parent, Err: err}
|
||||
}
|
||||
if dev != st.Dev {
|
||||
// Device differs from that of parent,
|
||||
// so definitely a mount point.
|
||||
return true, nil
|
||||
}
|
||||
// NB: this does not detect bind mounts on Linux.
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func normalizePath(path string) (realPath string, err error) {
|
||||
if realPath, err = filepath.Abs(path); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if realPath, err = filepath.EvalSymlinks(realPath); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if _, err := os.Stat(realPath); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return realPath, nil
|
||||
}
|
||||
|
||||
func mountedByMountinfo(path string) (bool, error) {
|
||||
entries, err := GetMounts(SingleEntryFilter(path))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return len(entries) > 0, nil
|
||||
}
|
||||
67
vendor/github.com/moby/sys/mountinfo/mountinfo.go
generated
vendored
Normal file
67
vendor/github.com/moby/sys/mountinfo/mountinfo.go
generated
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
package mountinfo
|
||||
|
||||
import (
|
||||
"os"
|
||||
)
|
||||
|
||||
// GetMounts retrieves a list of mounts for the current running process,
|
||||
// with an optional filter applied (use nil for no filter).
|
||||
func GetMounts(f FilterFunc) ([]*Info, error) {
|
||||
return parseMountTable(f)
|
||||
}
|
||||
|
||||
// Mounted determines if a specified path is a mount point. In case of any
|
||||
// error, false (and an error) is returned.
|
||||
//
|
||||
// If a non-existent path is specified, an appropriate error is returned.
|
||||
// In case the caller is not interested in this particular error, it should
|
||||
// be handled separately using e.g. errors.Is(err, fs.ErrNotExist).
|
||||
func Mounted(path string) (bool, error) {
|
||||
// root is always mounted
|
||||
if path == string(os.PathSeparator) {
|
||||
return true, nil
|
||||
}
|
||||
return mounted(path)
|
||||
}
|
||||
|
||||
// Info reveals information about a particular mounted filesystem. This
|
||||
// struct is populated from the content in the /proc/<pid>/mountinfo file.
|
||||
type Info struct {
|
||||
// ID is a unique identifier of the mount (may be reused after umount).
|
||||
ID int
|
||||
|
||||
// Parent is the ID of the parent mount (or of self for the root
|
||||
// of this mount namespace's mount tree).
|
||||
Parent int
|
||||
|
||||
// Major and Minor are the major and the minor components of the Dev
|
||||
// field of unix.Stat_t structure returned by unix.*Stat calls for
|
||||
// files on this filesystem.
|
||||
Major, Minor int
|
||||
|
||||
// Root is the pathname of the directory in the filesystem which forms
|
||||
// the root of this mount.
|
||||
Root string
|
||||
|
||||
// Mountpoint is the pathname of the mount point relative to the
|
||||
// process's root directory.
|
||||
Mountpoint string
|
||||
|
||||
// Options is a comma-separated list of mount options.
|
||||
Options string
|
||||
|
||||
// Optional are zero or more fields of the form "tag[:value]",
|
||||
// separated by a space. Currently, the possible optional fields are
|
||||
// "shared", "master", "propagate_from", and "unbindable". For more
|
||||
// information, see mount_namespaces(7) Linux man page.
|
||||
Optional string
|
||||
|
||||
// FSType is the filesystem type in the form "type[.subtype]".
|
||||
FSType string
|
||||
|
||||
// Source is filesystem-specific information, or "none".
|
||||
Source string
|
||||
|
||||
// VFSOptions is a comma-separated list of superblock options.
|
||||
VFSOptions string
|
||||
}
|
||||
56
vendor/github.com/moby/sys/mountinfo/mountinfo_bsd.go
generated
vendored
Normal file
56
vendor/github.com/moby/sys/mountinfo/mountinfo_bsd.go
generated
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
//go:build freebsd || openbsd || darwin
|
||||
// +build freebsd openbsd darwin
|
||||
|
||||
package mountinfo
|
||||
|
||||
import "golang.org/x/sys/unix"
|
||||
|
||||
// parseMountTable returns information about mounted filesystems
|
||||
func parseMountTable(filter FilterFunc) ([]*Info, error) {
|
||||
count, err := unix.Getfsstat(nil, unix.MNT_WAIT)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
entries := make([]unix.Statfs_t, count)
|
||||
_, err = unix.Getfsstat(entries, unix.MNT_WAIT)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var out []*Info
|
||||
for _, entry := range entries {
|
||||
var skip, stop bool
|
||||
mountinfo := getMountinfo(&entry)
|
||||
|
||||
if filter != nil {
|
||||
// filter out entries we're not interested in
|
||||
skip, stop = filter(mountinfo)
|
||||
if skip {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
out = append(out, mountinfo)
|
||||
if stop {
|
||||
break
|
||||
}
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func mounted(path string) (bool, error) {
|
||||
path, err := normalizePath(path)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
// Fast path: compare st.st_dev fields.
|
||||
// This should always work for FreeBSD and OpenBSD.
|
||||
mounted, err := mountedByStat(path)
|
||||
if err == nil {
|
||||
return mounted, nil
|
||||
}
|
||||
|
||||
// Fallback to parsing mountinfo
|
||||
return mountedByMountinfo(path)
|
||||
}
|
||||
63
vendor/github.com/moby/sys/mountinfo/mountinfo_filters.go
generated
vendored
Normal file
63
vendor/github.com/moby/sys/mountinfo/mountinfo_filters.go
generated
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
package mountinfo
|
||||
|
||||
import "strings"
|
||||
|
||||
// FilterFunc is a type defining a callback function for GetMount(),
|
||||
// used to filter out mountinfo entries we're not interested in,
|
||||
// and/or stop further processing if we found what we wanted.
|
||||
//
|
||||
// It takes a pointer to the Info struct (fully populated with all available
|
||||
// fields on the GOOS platform), and returns two booleans:
|
||||
//
|
||||
// skip: true if the entry should be skipped;
|
||||
//
|
||||
// stop: true if parsing should be stopped after the entry.
|
||||
type FilterFunc func(*Info) (skip, stop bool)
|
||||
|
||||
// PrefixFilter discards all entries whose mount points do not start with, or
|
||||
// are equal to the path specified in prefix. The prefix path must be absolute,
|
||||
// have all symlinks resolved, and cleaned (i.e. no extra slashes or dots).
|
||||
//
|
||||
// PrefixFilter treats prefix as a path, not a partial prefix, which means that
|
||||
// given "/foo", "/foo/bar" and "/foobar" entries, PrefixFilter("/foo") returns
|
||||
// "/foo" and "/foo/bar", and discards "/foobar".
|
||||
func PrefixFilter(prefix string) FilterFunc {
|
||||
return func(m *Info) (bool, bool) {
|
||||
skip := !strings.HasPrefix(m.Mountpoint+"/", prefix+"/")
|
||||
return skip, false
|
||||
}
|
||||
}
|
||||
|
||||
// SingleEntryFilter looks for a specific entry.
|
||||
func SingleEntryFilter(mp string) FilterFunc {
|
||||
return func(m *Info) (bool, bool) {
|
||||
if m.Mountpoint == mp {
|
||||
return false, true // don't skip, stop now
|
||||
}
|
||||
return true, false // skip, keep going
|
||||
}
|
||||
}
|
||||
|
||||
// ParentsFilter returns all entries whose mount points
|
||||
// can be parents of a path specified, discarding others.
|
||||
//
|
||||
// For example, given /var/lib/docker/something, entries
|
||||
// like /var/lib/docker, /var and / are returned.
|
||||
func ParentsFilter(path string) FilterFunc {
|
||||
return func(m *Info) (bool, bool) {
|
||||
skip := !strings.HasPrefix(path, m.Mountpoint)
|
||||
return skip, false
|
||||
}
|
||||
}
|
||||
|
||||
// FSTypeFilter returns all entries that match provided fstype(s).
|
||||
func FSTypeFilter(fstype ...string) FilterFunc {
|
||||
return func(m *Info) (bool, bool) {
|
||||
for _, t := range fstype {
|
||||
if m.FSType == t {
|
||||
return false, false // don't skip, keep going
|
||||
}
|
||||
}
|
||||
return true, false // skip, keep going
|
||||
}
|
||||
}
|
||||
14
vendor/github.com/moby/sys/mountinfo/mountinfo_freebsdlike.go
generated
vendored
Normal file
14
vendor/github.com/moby/sys/mountinfo/mountinfo_freebsdlike.go
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
//go:build freebsd || darwin
|
||||
// +build freebsd darwin
|
||||
|
||||
package mountinfo
|
||||
|
||||
import "golang.org/x/sys/unix"
|
||||
|
||||
func getMountinfo(entry *unix.Statfs_t) *Info {
|
||||
return &Info{
|
||||
Mountpoint: unix.ByteSliceToString(entry.Mntonname[:]),
|
||||
FSType: unix.ByteSliceToString(entry.Fstypename[:]),
|
||||
Source: unix.ByteSliceToString(entry.Mntfromname[:]),
|
||||
}
|
||||
}
|
||||
214
vendor/github.com/moby/sys/mountinfo/mountinfo_linux.go
generated
vendored
Normal file
214
vendor/github.com/moby/sys/mountinfo/mountinfo_linux.go
generated
vendored
Normal file
@@ -0,0 +1,214 @@
|
||||
package mountinfo
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// GetMountsFromReader retrieves a list of mounts from the
|
||||
// reader provided, with an optional filter applied (use nil
|
||||
// for no filter). This can be useful in tests or benchmarks
|
||||
// that provide fake mountinfo data, or when a source other
|
||||
// than /proc/self/mountinfo needs to be read from.
|
||||
//
|
||||
// This function is Linux-specific.
|
||||
func GetMountsFromReader(r io.Reader, filter FilterFunc) ([]*Info, error) {
|
||||
s := bufio.NewScanner(r)
|
||||
out := []*Info{}
|
||||
for s.Scan() {
|
||||
var err error
|
||||
|
||||
/*
|
||||
See http://man7.org/linux/man-pages/man5/proc.5.html
|
||||
|
||||
36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue
|
||||
(1)(2)(3) (4) (5) (6) (7) (8) (9) (10) (11)
|
||||
|
||||
(1) mount ID: unique identifier of the mount (may be reused after umount)
|
||||
(2) parent ID: ID of parent (or of self for the top of the mount tree)
|
||||
(3) major:minor: value of st_dev for files on filesystem
|
||||
(4) root: root of the mount within the filesystem
|
||||
(5) mount point: mount point relative to the process's root
|
||||
(6) mount options: per mount options
|
||||
(7) optional fields: zero or more fields of the form "tag[:value]"
|
||||
(8) separator: marks the end of the optional fields
|
||||
(9) filesystem type: name of filesystem of the form "type[.subtype]"
|
||||
(10) mount source: filesystem specific information or "none"
|
||||
(11) super options: per super block options
|
||||
|
||||
In other words, we have:
|
||||
* 6 mandatory fields (1)..(6)
|
||||
* 0 or more optional fields (7)
|
||||
* a separator field (8)
|
||||
* 3 mandatory fields (9)..(11)
|
||||
*/
|
||||
|
||||
text := s.Text()
|
||||
fields := strings.Split(text, " ")
|
||||
numFields := len(fields)
|
||||
if numFields < 10 {
|
||||
// should be at least 10 fields
|
||||
return nil, fmt.Errorf("parsing '%s' failed: not enough fields (%d)", text, numFields)
|
||||
}
|
||||
|
||||
// separator field
|
||||
sepIdx := numFields - 4
|
||||
// In Linux <= 3.9 mounting a cifs with spaces in a share
|
||||
// name (like "//srv/My Docs") _may_ end up having a space
|
||||
// in the last field of mountinfo (like "unc=//serv/My Docs").
|
||||
// Since kernel 3.10-rc1, cifs option "unc=" is ignored,
|
||||
// so spaces should not appear.
|
||||
//
|
||||
// Check for a separator, and work around the spaces bug
|
||||
for fields[sepIdx] != "-" {
|
||||
sepIdx--
|
||||
if sepIdx == 5 {
|
||||
return nil, fmt.Errorf("parsing '%s' failed: missing - separator", text)
|
||||
}
|
||||
}
|
||||
|
||||
p := &Info{}
|
||||
|
||||
p.Mountpoint, err = unescape(fields[4])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parsing '%s' failed: mount point: %w", fields[4], err)
|
||||
}
|
||||
p.FSType, err = unescape(fields[sepIdx+1])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parsing '%s' failed: fstype: %w", fields[sepIdx+1], err)
|
||||
}
|
||||
p.Source, err = unescape(fields[sepIdx+2])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parsing '%s' failed: source: %w", fields[sepIdx+2], err)
|
||||
}
|
||||
p.VFSOptions = fields[sepIdx+3]
|
||||
|
||||
// ignore any numbers parsing errors, as there should not be any
|
||||
p.ID, _ = strconv.Atoi(fields[0])
|
||||
p.Parent, _ = strconv.Atoi(fields[1])
|
||||
mm := strings.SplitN(fields[2], ":", 3)
|
||||
if len(mm) != 2 {
|
||||
return nil, fmt.Errorf("parsing '%s' failed: unexpected major:minor pair %s", text, mm)
|
||||
}
|
||||
p.Major, _ = strconv.Atoi(mm[0])
|
||||
p.Minor, _ = strconv.Atoi(mm[1])
|
||||
|
||||
p.Root, err = unescape(fields[3])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parsing '%s' failed: root: %w", fields[3], err)
|
||||
}
|
||||
|
||||
p.Options = fields[5]
|
||||
|
||||
// zero or more optional fields
|
||||
p.Optional = strings.Join(fields[6:sepIdx], " ")
|
||||
|
||||
// Run the filter after parsing all fields.
|
||||
var skip, stop bool
|
||||
if filter != nil {
|
||||
skip, stop = filter(p)
|
||||
if skip {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
out = append(out, p)
|
||||
if stop {
|
||||
break
|
||||
}
|
||||
}
|
||||
if err := s.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func parseMountTable(filter FilterFunc) ([]*Info, error) {
|
||||
f, err := os.Open("/proc/self/mountinfo")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
return GetMountsFromReader(f, filter)
|
||||
}
|
||||
|
||||
// PidMountInfo retrieves the list of mounts from a given process' mount
|
||||
// namespace. Unless there is a need to get mounts from a mount namespace
|
||||
// different from that of a calling process, use GetMounts.
|
||||
//
|
||||
// This function is Linux-specific.
|
||||
//
|
||||
// Deprecated: this will be removed before v1; use GetMountsFromReader with
|
||||
// opened /proc/<pid>/mountinfo as an argument instead.
|
||||
func PidMountInfo(pid int) ([]*Info, error) {
|
||||
f, err := os.Open(fmt.Sprintf("/proc/%d/mountinfo", pid))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
return GetMountsFromReader(f, nil)
|
||||
}
|
||||
|
||||
// A few specific characters in mountinfo path entries (root and mountpoint)
|
||||
// are escaped using a backslash followed by a character's ascii code in octal.
|
||||
//
|
||||
// space -- as \040
|
||||
// tab (aka \t) -- as \011
|
||||
// newline (aka \n) -- as \012
|
||||
// backslash (aka \\) -- as \134
|
||||
//
|
||||
// This function converts path from mountinfo back, i.e. it unescapes the above sequences.
|
||||
func unescape(path string) (string, error) {
|
||||
// try to avoid copying
|
||||
if strings.IndexByte(path, '\\') == -1 {
|
||||
return path, nil
|
||||
}
|
||||
|
||||
// The following code is UTF-8 transparent as it only looks for some
|
||||
// specific characters (backslash and 0..7) with values < utf8.RuneSelf,
|
||||
// and everything else is passed through as is.
|
||||
buf := make([]byte, len(path))
|
||||
bufLen := 0
|
||||
for i := 0; i < len(path); i++ {
|
||||
if path[i] != '\\' {
|
||||
buf[bufLen] = path[i]
|
||||
bufLen++
|
||||
continue
|
||||
}
|
||||
s := path[i:]
|
||||
if len(s) < 4 {
|
||||
// too short
|
||||
return "", fmt.Errorf("bad escape sequence %q: too short", s)
|
||||
}
|
||||
c := s[1]
|
||||
switch c {
|
||||
case '0', '1', '2', '3', '4', '5', '6', '7':
|
||||
v := c - '0'
|
||||
for j := 2; j < 4; j++ { // one digit already; two more
|
||||
if s[j] < '0' || s[j] > '7' {
|
||||
return "", fmt.Errorf("bad escape sequence %q: not a digit", s[:3])
|
||||
}
|
||||
x := s[j] - '0'
|
||||
v = (v << 3) | x
|
||||
}
|
||||
if v > 255 {
|
||||
return "", fmt.Errorf("bad escape sequence %q: out of range" + s[:3])
|
||||
}
|
||||
buf[bufLen] = v
|
||||
bufLen++
|
||||
i += 3
|
||||
continue
|
||||
default:
|
||||
return "", fmt.Errorf("bad escape sequence %q: not a digit" + s[:3])
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return string(buf[:bufLen]), nil
|
||||
}
|
||||
11
vendor/github.com/moby/sys/mountinfo/mountinfo_openbsd.go
generated
vendored
Normal file
11
vendor/github.com/moby/sys/mountinfo/mountinfo_openbsd.go
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
package mountinfo
|
||||
|
||||
import "golang.org/x/sys/unix"
|
||||
|
||||
func getMountinfo(entry *unix.Statfs_t) *Info {
|
||||
return &Info{
|
||||
Mountpoint: unix.ByteSliceToString(entry.F_mntonname[:]),
|
||||
FSType: unix.ByteSliceToString(entry.F_fstypename[:]),
|
||||
Source: unix.ByteSliceToString(entry.F_mntfromname[:]),
|
||||
}
|
||||
}
|
||||
19
vendor/github.com/moby/sys/mountinfo/mountinfo_unsupported.go
generated
vendored
Normal file
19
vendor/github.com/moby/sys/mountinfo/mountinfo_unsupported.go
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
//go:build !windows && !linux && !freebsd && !openbsd && !darwin
|
||||
// +build !windows,!linux,!freebsd,!openbsd,!darwin
|
||||
|
||||
package mountinfo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
var errNotImplemented = fmt.Errorf("not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
|
||||
|
||||
func parseMountTable(_ FilterFunc) ([]*Info, error) {
|
||||
return nil, errNotImplemented
|
||||
}
|
||||
|
||||
func mounted(path string) (bool, error) {
|
||||
return false, errNotImplemented
|
||||
}
|
||||
10
vendor/github.com/moby/sys/mountinfo/mountinfo_windows.go
generated
vendored
Normal file
10
vendor/github.com/moby/sys/mountinfo/mountinfo_windows.go
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
package mountinfo
|
||||
|
||||
func parseMountTable(_ FilterFunc) ([]*Info, error) {
|
||||
// Do NOT return an error!
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func mounted(_ string) (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
202
vendor/github.com/moby/sys/sequential/LICENSE
generated
vendored
Normal file
202
vendor/github.com/moby/sys/sequential/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
15
vendor/github.com/moby/sys/sequential/doc.go
generated
vendored
Normal file
15
vendor/github.com/moby/sys/sequential/doc.go
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
// Package sequential provides a set of functions for managing sequential
|
||||
// files on Windows.
|
||||
//
|
||||
// The origin of these functions are the golang OS and windows packages,
|
||||
// slightly modified to only cope with files, not directories due to the
|
||||
// specific use case.
|
||||
//
|
||||
// The alteration is to allow a file on Windows to be opened with
|
||||
// FILE_FLAG_SEQUENTIAL_SCAN (particular for docker load), to avoid eating
|
||||
// the standby list, particularly when accessing large files such as layer.tar.
|
||||
//
|
||||
// For non-Windows platforms, the package provides wrappers for the equivalents
|
||||
// in the os packages. They are passthrough on Unix platforms, and only relevant
|
||||
// on Windows.
|
||||
package sequential
|
||||
45
vendor/github.com/moby/sys/sequential/sequential_unix.go
generated
vendored
Normal file
45
vendor/github.com/moby/sys/sequential/sequential_unix.go
generated
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package sequential
|
||||
|
||||
import "os"
|
||||
|
||||
// Create creates the named file with mode 0666 (before umask), truncating
|
||||
// it if it already exists. If successful, methods on the returned
|
||||
// File can be used for I/O; the associated file descriptor has mode
|
||||
// O_RDWR.
|
||||
// If there is an error, it will be of type *PathError.
|
||||
func Create(name string) (*os.File, error) {
|
||||
return os.Create(name)
|
||||
}
|
||||
|
||||
// Open opens the named file for reading. If successful, methods on
|
||||
// the returned file can be used for reading; the associated file
|
||||
// descriptor has mode O_RDONLY.
|
||||
// If there is an error, it will be of type *PathError.
|
||||
func Open(name string) (*os.File, error) {
|
||||
return os.Open(name)
|
||||
}
|
||||
|
||||
// OpenFile is the generalized open call; most users will use Open
|
||||
// or Create instead. It opens the named file with specified flag
|
||||
// (O_RDONLY etc.) and perm, (0666 etc.) if applicable. If successful,
|
||||
// methods on the returned File can be used for I/O.
|
||||
// If there is an error, it will be of type *PathError.
|
||||
func OpenFile(name string, flag int, perm os.FileMode) (*os.File, error) {
|
||||
return os.OpenFile(name, flag, perm)
|
||||
}
|
||||
|
||||
// CreateTemp creates a new temporary file in the directory dir
|
||||
// with a name beginning with prefix, opens the file for reading
|
||||
// and writing, and returns the resulting *os.File.
|
||||
// If dir is the empty string, TempFile uses the default directory
|
||||
// for temporary files (see os.TempDir).
|
||||
// Multiple programs calling TempFile simultaneously
|
||||
// will not choose the same file. The caller can use f.Name()
|
||||
// to find the pathname of the file. It is the caller's responsibility
|
||||
// to remove the file when no longer needed.
|
||||
func CreateTemp(dir, prefix string) (f *os.File, err error) {
|
||||
return os.CreateTemp(dir, prefix)
|
||||
}
|
||||
161
vendor/github.com/moby/sys/sequential/sequential_windows.go
generated
vendored
Normal file
161
vendor/github.com/moby/sys/sequential/sequential_windows.go
generated
vendored
Normal file
@@ -0,0 +1,161 @@
|
||||
package sequential
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
// Create creates the named file with mode 0666 (before umask), truncating
|
||||
// it if it already exists. If successful, methods on the returned
|
||||
// File can be used for I/O; the associated file descriptor has mode
|
||||
// O_RDWR.
|
||||
// If there is an error, it will be of type *PathError.
|
||||
func Create(name string) (*os.File, error) {
|
||||
return OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0)
|
||||
}
|
||||
|
||||
// Open opens the named file for reading. If successful, methods on
|
||||
// the returned file can be used for reading; the associated file
|
||||
// descriptor has mode O_RDONLY.
|
||||
// If there is an error, it will be of type *PathError.
|
||||
func Open(name string) (*os.File, error) {
|
||||
return OpenFile(name, os.O_RDONLY, 0)
|
||||
}
|
||||
|
||||
// OpenFile is the generalized open call; most users will use Open
|
||||
// or Create instead.
|
||||
// If there is an error, it will be of type *PathError.
|
||||
func OpenFile(name string, flag int, _ os.FileMode) (*os.File, error) {
|
||||
if name == "" {
|
||||
return nil, &os.PathError{Op: "open", Path: name, Err: syscall.ENOENT}
|
||||
}
|
||||
r, err := openFileSequential(name, flag, 0)
|
||||
if err == nil {
|
||||
return r, nil
|
||||
}
|
||||
return nil, &os.PathError{Op: "open", Path: name, Err: err}
|
||||
}
|
||||
|
||||
func openFileSequential(name string, flag int, _ os.FileMode) (file *os.File, err error) {
|
||||
r, e := openSequential(name, flag|windows.O_CLOEXEC, 0)
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
return os.NewFile(uintptr(r), name), nil
|
||||
}
|
||||
|
||||
func makeInheritSa() *windows.SecurityAttributes {
|
||||
var sa windows.SecurityAttributes
|
||||
sa.Length = uint32(unsafe.Sizeof(sa))
|
||||
sa.InheritHandle = 1
|
||||
return &sa
|
||||
}
|
||||
|
||||
func openSequential(path string, mode int, _ uint32) (fd windows.Handle, err error) {
|
||||
if len(path) == 0 {
|
||||
return windows.InvalidHandle, windows.ERROR_FILE_NOT_FOUND
|
||||
}
|
||||
pathp, err := windows.UTF16PtrFromString(path)
|
||||
if err != nil {
|
||||
return windows.InvalidHandle, err
|
||||
}
|
||||
var access uint32
|
||||
switch mode & (windows.O_RDONLY | windows.O_WRONLY | windows.O_RDWR) {
|
||||
case windows.O_RDONLY:
|
||||
access = windows.GENERIC_READ
|
||||
case windows.O_WRONLY:
|
||||
access = windows.GENERIC_WRITE
|
||||
case windows.O_RDWR:
|
||||
access = windows.GENERIC_READ | windows.GENERIC_WRITE
|
||||
}
|
||||
if mode&windows.O_CREAT != 0 {
|
||||
access |= windows.GENERIC_WRITE
|
||||
}
|
||||
if mode&windows.O_APPEND != 0 {
|
||||
access &^= windows.GENERIC_WRITE
|
||||
access |= windows.FILE_APPEND_DATA
|
||||
}
|
||||
sharemode := uint32(windows.FILE_SHARE_READ | windows.FILE_SHARE_WRITE)
|
||||
var sa *windows.SecurityAttributes
|
||||
if mode&windows.O_CLOEXEC == 0 {
|
||||
sa = makeInheritSa()
|
||||
}
|
||||
var createmode uint32
|
||||
switch {
|
||||
case mode&(windows.O_CREAT|windows.O_EXCL) == (windows.O_CREAT | windows.O_EXCL):
|
||||
createmode = windows.CREATE_NEW
|
||||
case mode&(windows.O_CREAT|windows.O_TRUNC) == (windows.O_CREAT | windows.O_TRUNC):
|
||||
createmode = windows.CREATE_ALWAYS
|
||||
case mode&windows.O_CREAT == windows.O_CREAT:
|
||||
createmode = windows.OPEN_ALWAYS
|
||||
case mode&windows.O_TRUNC == windows.O_TRUNC:
|
||||
createmode = windows.TRUNCATE_EXISTING
|
||||
default:
|
||||
createmode = windows.OPEN_EXISTING
|
||||
}
|
||||
// Use FILE_FLAG_SEQUENTIAL_SCAN rather than FILE_ATTRIBUTE_NORMAL as implemented in golang.
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx
|
||||
const fileFlagSequentialScan = 0x08000000 // FILE_FLAG_SEQUENTIAL_SCAN
|
||||
h, e := windows.CreateFile(pathp, access, sharemode, sa, createmode, fileFlagSequentialScan, 0)
|
||||
return h, e
|
||||
}
|
||||
|
||||
// Helpers for CreateTemp
|
||||
var rand uint32
|
||||
var randmu sync.Mutex
|
||||
|
||||
func reseed() uint32 {
|
||||
return uint32(time.Now().UnixNano() + int64(os.Getpid()))
|
||||
}
|
||||
|
||||
func nextSuffix() string {
|
||||
randmu.Lock()
|
||||
r := rand
|
||||
if r == 0 {
|
||||
r = reseed()
|
||||
}
|
||||
r = r*1664525 + 1013904223 // constants from Numerical Recipes
|
||||
rand = r
|
||||
randmu.Unlock()
|
||||
return strconv.Itoa(int(1e9 + r%1e9))[1:]
|
||||
}
|
||||
|
||||
// CreateTemp is a copy of os.CreateTemp, modified to use sequential
|
||||
// file access. Below is the original comment from golang:
|
||||
// TempFile creates a new temporary file in the directory dir
|
||||
// with a name beginning with prefix, opens the file for reading
|
||||
// and writing, and returns the resulting *os.File.
|
||||
// If dir is the empty string, TempFile uses the default directory
|
||||
// for temporary files (see os.TempDir).
|
||||
// Multiple programs calling TempFile simultaneously
|
||||
// will not choose the same file. The caller can use f.Name()
|
||||
// to find the pathname of the file. It is the caller's responsibility
|
||||
// to remove the file when no longer needed.
|
||||
func CreateTemp(dir, prefix string) (f *os.File, err error) {
|
||||
if dir == "" {
|
||||
dir = os.TempDir()
|
||||
}
|
||||
|
||||
nconflict := 0
|
||||
for i := 0; i < 10000; i++ {
|
||||
name := filepath.Join(dir, prefix+nextSuffix())
|
||||
f, err = OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0o600)
|
||||
if os.IsExist(err) {
|
||||
if nconflict++; nconflict > 10 {
|
||||
randmu.Lock()
|
||||
rand = reseed()
|
||||
randmu.Unlock()
|
||||
}
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
return
|
||||
}
|
||||
202
vendor/github.com/moby/sys/signal/LICENSE
generated
vendored
Normal file
202
vendor/github.com/moby/sys/signal/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
61
vendor/github.com/moby/sys/signal/signal.go
generated
vendored
Normal file
61
vendor/github.com/moby/sys/signal/signal.go
generated
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
// Package signal provides helper functions for dealing with signals across
|
||||
// various operating systems.
|
||||
package signal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/signal"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// CatchAll catches all signals and relays them to the specified channel.
|
||||
// SIGURG is not handled, as it's used by the Go runtime to support
|
||||
// preemptable system calls.
|
||||
func CatchAll(sigc chan os.Signal) {
|
||||
var handledSigs []os.Signal
|
||||
for n, s := range SignalMap {
|
||||
if n == "URG" {
|
||||
// Do not handle SIGURG, as in go1.14+, the go runtime issues
|
||||
// SIGURG as an interrupt to support preemptable system calls on Linux.
|
||||
continue
|
||||
}
|
||||
handledSigs = append(handledSigs, s)
|
||||
}
|
||||
signal.Notify(sigc, handledSigs...)
|
||||
}
|
||||
|
||||
// StopCatch stops catching the signals and closes the specified channel.
|
||||
func StopCatch(sigc chan os.Signal) {
|
||||
signal.Stop(sigc)
|
||||
close(sigc)
|
||||
}
|
||||
|
||||
// ParseSignal translates a string to a valid syscall signal.
|
||||
// It returns an error if the signal map doesn't include the given signal.
|
||||
func ParseSignal(rawSignal string) (syscall.Signal, error) {
|
||||
s, err := strconv.Atoi(rawSignal)
|
||||
if err == nil {
|
||||
if s == 0 {
|
||||
return -1, fmt.Errorf("invalid signal: %s", rawSignal)
|
||||
}
|
||||
return syscall.Signal(s), nil
|
||||
}
|
||||
signal, ok := SignalMap[strings.TrimPrefix(strings.ToUpper(rawSignal), "SIG")]
|
||||
if !ok {
|
||||
return -1, fmt.Errorf("invalid signal: %s", rawSignal)
|
||||
}
|
||||
return signal, nil
|
||||
}
|
||||
|
||||
// ValidSignalForPlatform returns true if a signal is valid on the platform
|
||||
func ValidSignalForPlatform(sig syscall.Signal) bool {
|
||||
for _, v := range SignalMap {
|
||||
if v == sig {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
41
vendor/github.com/moby/sys/signal/signal_darwin.go
generated
vendored
Normal file
41
vendor/github.com/moby/sys/signal/signal_darwin.go
generated
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
package signal
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// SignalMap is a map of Darwin signals.
|
||||
var SignalMap = map[string]syscall.Signal{
|
||||
"ABRT": syscall.SIGABRT,
|
||||
"ALRM": syscall.SIGALRM,
|
||||
"BUS": syscall.SIGBUS,
|
||||
"CHLD": syscall.SIGCHLD,
|
||||
"CONT": syscall.SIGCONT,
|
||||
"EMT": syscall.SIGEMT,
|
||||
"FPE": syscall.SIGFPE,
|
||||
"HUP": syscall.SIGHUP,
|
||||
"ILL": syscall.SIGILL,
|
||||
"INFO": syscall.SIGINFO,
|
||||
"INT": syscall.SIGINT,
|
||||
"IO": syscall.SIGIO,
|
||||
"IOT": syscall.SIGIOT,
|
||||
"KILL": syscall.SIGKILL,
|
||||
"PIPE": syscall.SIGPIPE,
|
||||
"PROF": syscall.SIGPROF,
|
||||
"QUIT": syscall.SIGQUIT,
|
||||
"SEGV": syscall.SIGSEGV,
|
||||
"STOP": syscall.SIGSTOP,
|
||||
"SYS": syscall.SIGSYS,
|
||||
"TERM": syscall.SIGTERM,
|
||||
"TRAP": syscall.SIGTRAP,
|
||||
"TSTP": syscall.SIGTSTP,
|
||||
"TTIN": syscall.SIGTTIN,
|
||||
"TTOU": syscall.SIGTTOU,
|
||||
"URG": syscall.SIGURG,
|
||||
"USR1": syscall.SIGUSR1,
|
||||
"USR2": syscall.SIGUSR2,
|
||||
"VTALRM": syscall.SIGVTALRM,
|
||||
"WINCH": syscall.SIGWINCH,
|
||||
"XCPU": syscall.SIGXCPU,
|
||||
"XFSZ": syscall.SIGXFSZ,
|
||||
}
|
||||
43
vendor/github.com/moby/sys/signal/signal_freebsd.go
generated
vendored
Normal file
43
vendor/github.com/moby/sys/signal/signal_freebsd.go
generated
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
package signal
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// SignalMap is a map of FreeBSD signals.
|
||||
var SignalMap = map[string]syscall.Signal{
|
||||
"ABRT": syscall.SIGABRT,
|
||||
"ALRM": syscall.SIGALRM,
|
||||
"BUS": syscall.SIGBUS,
|
||||
"CHLD": syscall.SIGCHLD,
|
||||
"CONT": syscall.SIGCONT,
|
||||
"EMT": syscall.SIGEMT,
|
||||
"FPE": syscall.SIGFPE,
|
||||
"HUP": syscall.SIGHUP,
|
||||
"ILL": syscall.SIGILL,
|
||||
"INFO": syscall.SIGINFO,
|
||||
"INT": syscall.SIGINT,
|
||||
"IO": syscall.SIGIO,
|
||||
"IOT": syscall.SIGIOT,
|
||||
"KILL": syscall.SIGKILL,
|
||||
"LWP": syscall.SIGLWP,
|
||||
"PIPE": syscall.SIGPIPE,
|
||||
"PROF": syscall.SIGPROF,
|
||||
"QUIT": syscall.SIGQUIT,
|
||||
"SEGV": syscall.SIGSEGV,
|
||||
"STOP": syscall.SIGSTOP,
|
||||
"SYS": syscall.SIGSYS,
|
||||
"TERM": syscall.SIGTERM,
|
||||
"THR": syscall.SIGTHR,
|
||||
"TRAP": syscall.SIGTRAP,
|
||||
"TSTP": syscall.SIGTSTP,
|
||||
"TTIN": syscall.SIGTTIN,
|
||||
"TTOU": syscall.SIGTTOU,
|
||||
"URG": syscall.SIGURG,
|
||||
"USR1": syscall.SIGUSR1,
|
||||
"USR2": syscall.SIGUSR2,
|
||||
"VTALRM": syscall.SIGVTALRM,
|
||||
"WINCH": syscall.SIGWINCH,
|
||||
"XCPU": syscall.SIGXCPU,
|
||||
"XFSZ": syscall.SIGXFSZ,
|
||||
}
|
||||
84
vendor/github.com/moby/sys/signal/signal_linux.go
generated
vendored
Normal file
84
vendor/github.com/moby/sys/signal/signal_linux.go
generated
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
//go:build !mips && !mipsle && !mips64 && !mips64le
|
||||
// +build !mips,!mipsle,!mips64,!mips64le
|
||||
|
||||
package signal
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
const (
|
||||
sigrtmin = 34
|
||||
sigrtmax = 64
|
||||
)
|
||||
|
||||
// SignalMap is a map of Linux signals.
|
||||
var SignalMap = map[string]syscall.Signal{
|
||||
"ABRT": unix.SIGABRT,
|
||||
"ALRM": unix.SIGALRM,
|
||||
"BUS": unix.SIGBUS,
|
||||
"CHLD": unix.SIGCHLD,
|
||||
"CLD": unix.SIGCLD,
|
||||
"CONT": unix.SIGCONT,
|
||||
"FPE": unix.SIGFPE,
|
||||
"HUP": unix.SIGHUP,
|
||||
"ILL": unix.SIGILL,
|
||||
"INT": unix.SIGINT,
|
||||
"IO": unix.SIGIO,
|
||||
"IOT": unix.SIGIOT,
|
||||
"KILL": unix.SIGKILL,
|
||||
"PIPE": unix.SIGPIPE,
|
||||
"POLL": unix.SIGPOLL,
|
||||
"PROF": unix.SIGPROF,
|
||||
"PWR": unix.SIGPWR,
|
||||
"QUIT": unix.SIGQUIT,
|
||||
"SEGV": unix.SIGSEGV,
|
||||
"STKFLT": unix.SIGSTKFLT,
|
||||
"STOP": unix.SIGSTOP,
|
||||
"SYS": unix.SIGSYS,
|
||||
"TERM": unix.SIGTERM,
|
||||
"TRAP": unix.SIGTRAP,
|
||||
"TSTP": unix.SIGTSTP,
|
||||
"TTIN": unix.SIGTTIN,
|
||||
"TTOU": unix.SIGTTOU,
|
||||
"URG": unix.SIGURG,
|
||||
"USR1": unix.SIGUSR1,
|
||||
"USR2": unix.SIGUSR2,
|
||||
"VTALRM": unix.SIGVTALRM,
|
||||
"WINCH": unix.SIGWINCH,
|
||||
"XCPU": unix.SIGXCPU,
|
||||
"XFSZ": unix.SIGXFSZ,
|
||||
"RTMIN": sigrtmin,
|
||||
"RTMIN+1": sigrtmin + 1,
|
||||
"RTMIN+2": sigrtmin + 2,
|
||||
"RTMIN+3": sigrtmin + 3,
|
||||
"RTMIN+4": sigrtmin + 4,
|
||||
"RTMIN+5": sigrtmin + 5,
|
||||
"RTMIN+6": sigrtmin + 6,
|
||||
"RTMIN+7": sigrtmin + 7,
|
||||
"RTMIN+8": sigrtmin + 8,
|
||||
"RTMIN+9": sigrtmin + 9,
|
||||
"RTMIN+10": sigrtmin + 10,
|
||||
"RTMIN+11": sigrtmin + 11,
|
||||
"RTMIN+12": sigrtmin + 12,
|
||||
"RTMIN+13": sigrtmin + 13,
|
||||
"RTMIN+14": sigrtmin + 14,
|
||||
"RTMIN+15": sigrtmin + 15,
|
||||
"RTMAX-14": sigrtmax - 14,
|
||||
"RTMAX-13": sigrtmax - 13,
|
||||
"RTMAX-12": sigrtmax - 12,
|
||||
"RTMAX-11": sigrtmax - 11,
|
||||
"RTMAX-10": sigrtmax - 10,
|
||||
"RTMAX-9": sigrtmax - 9,
|
||||
"RTMAX-8": sigrtmax - 8,
|
||||
"RTMAX-7": sigrtmax - 7,
|
||||
"RTMAX-6": sigrtmax - 6,
|
||||
"RTMAX-5": sigrtmax - 5,
|
||||
"RTMAX-4": sigrtmax - 4,
|
||||
"RTMAX-3": sigrtmax - 3,
|
||||
"RTMAX-2": sigrtmax - 2,
|
||||
"RTMAX-1": sigrtmax - 1,
|
||||
"RTMAX": sigrtmax,
|
||||
}
|
||||
85
vendor/github.com/moby/sys/signal/signal_linux_mipsx.go
generated
vendored
Normal file
85
vendor/github.com/moby/sys/signal/signal_linux_mipsx.go
generated
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
//go:build linux && (mips || mipsle || mips64 || mips64le)
|
||||
// +build linux
|
||||
// +build mips mipsle mips64 mips64le
|
||||
|
||||
package signal
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
const (
|
||||
sigrtmin = 34
|
||||
sigrtmax = 127
|
||||
)
|
||||
|
||||
// SignalMap is a map of Linux signals.
|
||||
var SignalMap = map[string]syscall.Signal{
|
||||
"ABRT": unix.SIGABRT,
|
||||
"ALRM": unix.SIGALRM,
|
||||
"BUS": unix.SIGBUS,
|
||||
"CHLD": unix.SIGCHLD,
|
||||
"CLD": unix.SIGCLD,
|
||||
"CONT": unix.SIGCONT,
|
||||
"FPE": unix.SIGFPE,
|
||||
"HUP": unix.SIGHUP,
|
||||
"ILL": unix.SIGILL,
|
||||
"INT": unix.SIGINT,
|
||||
"IO": unix.SIGIO,
|
||||
"IOT": unix.SIGIOT,
|
||||
"KILL": unix.SIGKILL,
|
||||
"PIPE": unix.SIGPIPE,
|
||||
"POLL": unix.SIGPOLL,
|
||||
"PROF": unix.SIGPROF,
|
||||
"PWR": unix.SIGPWR,
|
||||
"QUIT": unix.SIGQUIT,
|
||||
"SEGV": unix.SIGSEGV,
|
||||
"EMT": unix.SIGEMT,
|
||||
"STOP": unix.SIGSTOP,
|
||||
"SYS": unix.SIGSYS,
|
||||
"TERM": unix.SIGTERM,
|
||||
"TRAP": unix.SIGTRAP,
|
||||
"TSTP": unix.SIGTSTP,
|
||||
"TTIN": unix.SIGTTIN,
|
||||
"TTOU": unix.SIGTTOU,
|
||||
"URG": unix.SIGURG,
|
||||
"USR1": unix.SIGUSR1,
|
||||
"USR2": unix.SIGUSR2,
|
||||
"VTALRM": unix.SIGVTALRM,
|
||||
"WINCH": unix.SIGWINCH,
|
||||
"XCPU": unix.SIGXCPU,
|
||||
"XFSZ": unix.SIGXFSZ,
|
||||
"RTMIN": sigrtmin,
|
||||
"RTMIN+1": sigrtmin + 1,
|
||||
"RTMIN+2": sigrtmin + 2,
|
||||
"RTMIN+3": sigrtmin + 3,
|
||||
"RTMIN+4": sigrtmin + 4,
|
||||
"RTMIN+5": sigrtmin + 5,
|
||||
"RTMIN+6": sigrtmin + 6,
|
||||
"RTMIN+7": sigrtmin + 7,
|
||||
"RTMIN+8": sigrtmin + 8,
|
||||
"RTMIN+9": sigrtmin + 9,
|
||||
"RTMIN+10": sigrtmin + 10,
|
||||
"RTMIN+11": sigrtmin + 11,
|
||||
"RTMIN+12": sigrtmin + 12,
|
||||
"RTMIN+13": sigrtmin + 13,
|
||||
"RTMIN+14": sigrtmin + 14,
|
||||
"RTMIN+15": sigrtmin + 15,
|
||||
"RTMAX-14": sigrtmax - 14,
|
||||
"RTMAX-13": sigrtmax - 13,
|
||||
"RTMAX-12": sigrtmax - 12,
|
||||
"RTMAX-11": sigrtmax - 11,
|
||||
"RTMAX-10": sigrtmax - 10,
|
||||
"RTMAX-9": sigrtmax - 9,
|
||||
"RTMAX-8": sigrtmax - 8,
|
||||
"RTMAX-7": sigrtmax - 7,
|
||||
"RTMAX-6": sigrtmax - 6,
|
||||
"RTMAX-5": sigrtmax - 5,
|
||||
"RTMAX-4": sigrtmax - 4,
|
||||
"RTMAX-3": sigrtmax - 3,
|
||||
"RTMAX-2": sigrtmax - 2,
|
||||
"RTMAX-1": sigrtmax - 1,
|
||||
"RTMAX": sigrtmax,
|
||||
}
|
||||
20
vendor/github.com/moby/sys/signal/signal_unix.go
generated
vendored
Normal file
20
vendor/github.com/moby/sys/signal/signal_unix.go
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package signal
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// Signals used in cli/command (no windows equivalent, use
|
||||
// invalid signals so they don't get handled)
|
||||
|
||||
const (
|
||||
// SIGCHLD is a signal sent to a process when a child process terminates, is interrupted, or resumes after being interrupted.
|
||||
SIGCHLD = syscall.SIGCHLD
|
||||
// SIGWINCH is a signal sent to a process when its controlling terminal changes its size
|
||||
SIGWINCH = syscall.SIGWINCH
|
||||
// SIGPIPE is a signal sent to a process when a pipe is written to before the other end is open for reading
|
||||
SIGPIPE = syscall.SIGPIPE
|
||||
)
|
||||
11
vendor/github.com/moby/sys/signal/signal_unsupported.go
generated
vendored
Normal file
11
vendor/github.com/moby/sys/signal/signal_unsupported.go
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
//go:build !linux && !darwin && !freebsd && !windows
|
||||
// +build !linux,!darwin,!freebsd,!windows
|
||||
|
||||
package signal
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// SignalMap is an empty map of signals for unsupported platform.
|
||||
var SignalMap = map[string]syscall.Signal{}
|
||||
57
vendor/github.com/moby/sys/signal/signal_windows.go
generated
vendored
Normal file
57
vendor/github.com/moby/sys/signal/signal_windows.go
generated
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
package signal
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
// Signals used in cli/command (no windows equivalent, use
|
||||
// invalid signals so they don't get handled)
|
||||
const (
|
||||
SIGCHLD = syscall.Signal(0xff)
|
||||
SIGWINCH = syscall.Signal(0xff)
|
||||
SIGPIPE = syscall.Signal(0xff)
|
||||
)
|
||||
|
||||
// SignalMap is a map of "supported" signals. As per the comment in GOLang's
|
||||
// ztypes_windows.go: "More invented values for signals". Windows doesn't
|
||||
// really support signals in any way, shape or form that Unix does.
|
||||
var SignalMap = map[string]syscall.Signal{
|
||||
"ABRT": syscall.Signal(windows.SIGABRT),
|
||||
"ALRM": syscall.Signal(windows.SIGALRM),
|
||||
"BUS": syscall.Signal(windows.SIGBUS),
|
||||
"FPE": syscall.Signal(windows.SIGFPE),
|
||||
"HUP": syscall.Signal(windows.SIGHUP),
|
||||
"ILL": syscall.Signal(windows.SIGILL),
|
||||
"INT": syscall.Signal(windows.SIGINT),
|
||||
"KILL": syscall.Signal(windows.SIGKILL),
|
||||
"PIPE": syscall.Signal(windows.SIGPIPE),
|
||||
"QUIT": syscall.Signal(windows.SIGQUIT),
|
||||
"SEGV": syscall.Signal(windows.SIGSEGV),
|
||||
"TERM": syscall.Signal(windows.SIGTERM),
|
||||
"TRAP": syscall.Signal(windows.SIGTRAP),
|
||||
|
||||
// additional linux signals supported for LCOW
|
||||
"CHLD": syscall.Signal(0x11),
|
||||
"CLD": syscall.Signal(0x11),
|
||||
"CONT": syscall.Signal(0x12),
|
||||
"IO": syscall.Signal(0x1d),
|
||||
"IOT": syscall.Signal(0x6),
|
||||
"POLL": syscall.Signal(0x1d),
|
||||
"PROF": syscall.Signal(0x1b),
|
||||
"PWR": syscall.Signal(0x1e),
|
||||
"STKFLT": syscall.Signal(0x10),
|
||||
"STOP": syscall.Signal(0x13),
|
||||
"SYS": syscall.Signal(0x1f),
|
||||
"TSTP": syscall.Signal(0x14),
|
||||
"TTIN": syscall.Signal(0x15),
|
||||
"TTOU": syscall.Signal(0x16),
|
||||
"URG": syscall.Signal(0x17),
|
||||
"USR1": syscall.Signal(0xa),
|
||||
"USR2": syscall.Signal(0xc),
|
||||
"VTALRM": syscall.Signal(0x1a),
|
||||
"WINCH": syscall.Signal(0x1c),
|
||||
"XCPU": syscall.Signal(0x18),
|
||||
"XFSZ": syscall.Signal(0x19),
|
||||
}
|
||||
Reference in New Issue
Block a user