mirror of
				https://gitea.com/Lydanne/buildx.git
				synced 2025-11-04 10:03:42 +08:00 
			
		
		
		
	vendor: update buildkit
Signed-off-by: CrazyMax <crazy-max@users.noreply.github.com>
This commit is contained in:
		
							
								
								
									
										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
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										5
									
								
								vendor/github.com/moby/spdystream/go.mod
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								vendor/github.com/moby/spdystream/go.mod
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
			
		||||
module github.com/moby/spdystream
 | 
			
		||||
 | 
			
		||||
go 1.13
 | 
			
		||||
 | 
			
		||||
require github.com/gorilla/websocket v1.4.2
 | 
			
		||||
							
								
								
									
										2
									
								
								vendor/github.com/moby/spdystream/go.sum
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/moby/spdystream/go.sum
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,2 @@
 | 
			
		||||
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
 | 
			
		||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
 | 
			
		||||
							
								
								
									
										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...)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user