Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
K
k3s
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Jacklull
k3s
Commits
e5ed62e8
Commit
e5ed62e8
authored
Jul 15, 2016
by
Timothy St. Clair
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Update golang.org/x/net godep for http2 issues being seen during scale
tests
parent
6193335b
Hide whitespace changes
Inline
Side-by-side
Showing
31 changed files
with
2163 additions
and
1183 deletions
+2163
-1183
Godeps.json
Godeps/Godeps.json
+15
-15
LICENSES
Godeps/LICENSES
+35
-0
context.go
vendor/golang.org/x/net/context/context.go
+2
-293
cancelreq.go
vendor/golang.org/x/net/context/ctxhttp/cancelreq.go
+0
-19
cancelreq_go14.go
vendor/golang.org/x/net/context/ctxhttp/cancelreq_go14.go
+0
-23
ctxhttp.go
vendor/golang.org/x/net/context/ctxhttp/ctxhttp.go
+10
-86
ctxhttp_pre17.go
vendor/golang.org/x/net/context/ctxhttp/ctxhttp_pre17.go
+147
-0
go17.go
vendor/golang.org/x/net/context/go17.go
+72
-0
pre_go17.go
vendor/golang.org/x/net/context/pre_go17.go
+300
-0
client_conn_pool.go
vendor/golang.org/x/net/http2/client_conn_pool.go
+31
-1
configure_transport.go
vendor/golang.org/x/net/http2/configure_transport.go
+1
-10
errors.go
vendor/golang.org/x/net/http2/errors.go
+33
-1
frame.go
vendor/golang.org/x/net/http2/frame.go
+244
-6
go15.go
vendor/golang.org/x/net/http2/go15.go
+0
-11
go16.go
vendor/golang.org/x/net/http2/go16.go
+43
-0
go17.go
vendor/golang.org/x/net/http2/go17.go
+94
-0
encode.go
vendor/golang.org/x/net/http2/hpack/encode.go
+1
-1
hpack.go
vendor/golang.org/x/net/http2/hpack/hpack.go
+12
-3
huffman.go
vendor/golang.org/x/net/http2/hpack/huffman.go
+32
-10
http2.go
vendor/golang.org/x/net/http2/http2.go
+43
-121
not_go15.go
vendor/golang.org/x/net/http2/not_go15.go
+0
-11
not_go16.go
vendor/golang.org/x/net/http2/not_go16.go
+34
-1
not_go17.go
vendor/golang.org/x/net/http2/not_go17.go
+51
-0
pipe.go
vendor/golang.org/x/net/http2/pipe.go
+6
-0
server.go
vendor/golang.org/x/net/http2/server.go
+213
-258
transport.go
vendor/golang.org/x/net/http2/transport.go
+409
-291
write.go
vendor/golang.org/x/net/http2/write.go
+12
-11
httplex.go
vendor/golang.org/x/net/lex/httplex/httplex.go
+312
-0
trace.go
vendor/golang.org/x/net/trace/trace.go
+9
-5
hybi.go
vendor/golang.org/x/net/websocket/hybi.go
+0
-3
websocket.go
vendor/golang.org/x/net/websocket/websocket.go
+2
-3
No files found.
Godeps/Godeps.json
View file @
e5ed62e8
...
...
@@ -225,7 +225,7 @@
},
{
"ImportPath"
:
"github.com/codegangsta/negroni"
,
"Comment"
:
"v0.1
.0
-62-g8d75e11"
,
"Comment"
:
"v0.1-62-g8d75e11"
,
"Rev"
:
"8d75e11374a1928608c906fe745b538483e7aeb2"
},
{
...
...
@@ -1987,43 +1987,47 @@
},
{
"ImportPath"
:
"golang.org/x/net/context"
,
"Rev"
:
"
62685c2d7ca23c807425dca88b11a3e2323dab41
"
"Rev"
:
"
e90d6d0afc4c315a0d87a568ae68577cc15149a0
"
},
{
"ImportPath"
:
"golang.org/x/net/context/ctxhttp"
,
"Rev"
:
"
62685c2d7ca23c807425dca88b11a3e2323dab41
"
"Rev"
:
"
e90d6d0afc4c315a0d87a568ae68577cc15149a0
"
},
{
"ImportPath"
:
"golang.org/x/net/html"
,
"Rev"
:
"
62685c2d7ca23c807425dca88b11a3e2323dab41
"
"Rev"
:
"
e90d6d0afc4c315a0d87a568ae68577cc15149a0
"
},
{
"ImportPath"
:
"golang.org/x/net/html/atom"
,
"Rev"
:
"
62685c2d7ca23c807425dca88b11a3e2323dab41
"
"Rev"
:
"
e90d6d0afc4c315a0d87a568ae68577cc15149a0
"
},
{
"ImportPath"
:
"golang.org/x/net/http2"
,
"Rev"
:
"
62685c2d7ca23c807425dca88b11a3e2323dab41
"
"Rev"
:
"
e90d6d0afc4c315a0d87a568ae68577cc15149a0
"
},
{
"ImportPath"
:
"golang.org/x/net/http2/hpack"
,
"Rev"
:
"
62685c2d7ca23c807425dca88b11a3e2323dab41
"
"Rev"
:
"
e90d6d0afc4c315a0d87a568ae68577cc15149a0
"
},
{
"ImportPath"
:
"golang.org/x/net/internal/timeseries"
,
"Rev"
:
"62685c2d7ca23c807425dca88b11a3e2323dab41"
"Rev"
:
"e90d6d0afc4c315a0d87a568ae68577cc15149a0"
},
{
"ImportPath"
:
"golang.org/x/net/lex/httplex"
,
"Rev"
:
"e90d6d0afc4c315a0d87a568ae68577cc15149a0"
},
{
"ImportPath"
:
"golang.org/x/net/proxy"
,
"Rev"
:
"
62685c2d7ca23c807425dca88b11a3e2323dab41
"
"Rev"
:
"
e90d6d0afc4c315a0d87a568ae68577cc15149a0
"
},
{
"ImportPath"
:
"golang.org/x/net/trace"
,
"Rev"
:
"
62685c2d7ca23c807425dca88b11a3e2323dab41
"
"Rev"
:
"
e90d6d0afc4c315a0d87a568ae68577cc15149a0
"
},
{
"ImportPath"
:
"golang.org/x/net/websocket"
,
"Rev"
:
"
62685c2d7ca23c807425dca88b11a3e2323dab41
"
"Rev"
:
"
e90d6d0afc4c315a0d87a568ae68577cc15149a0
"
},
{
"ImportPath"
:
"golang.org/x/oauth2"
,
...
...
@@ -2119,22 +2123,18 @@
},
{
"ImportPath"
:
"gopkg.in/gcfg.v1"
,
"Comment"
:
"v1.0.0"
,
"Rev"
:
"083575c3955c85df16fe9590cceab64d03f5eb6e"
},
{
"ImportPath"
:
"gopkg.in/gcfg.v1/scanner"
,
"Comment"
:
"v1.0.0"
,
"Rev"
:
"083575c3955c85df16fe9590cceab64d03f5eb6e"
},
{
"ImportPath"
:
"gopkg.in/gcfg.v1/token"
,
"Comment"
:
"v1.0.0"
,
"Rev"
:
"083575c3955c85df16fe9590cceab64d03f5eb6e"
},
{
"ImportPath"
:
"gopkg.in/gcfg.v1/types"
,
"Comment"
:
"v1.0.0"
,
"Rev"
:
"083575c3955c85df16fe9590cceab64d03f5eb6e"
},
{
...
...
Godeps/LICENSES
View file @
e5ed62e8
...
...
@@ -62698,6 +62698,41 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
================================================================================
=
vendor
/
golang
.
org
/
x
/
net
/
lex
/
httplex
licensed
under
:
=
Copyright
(
c
)
2009
The
Go
Authors
.
All
rights
reserved
.
Redistribution
and
use
in
source
and
binary
forms
,
with
or
without
modification
,
are
permitted
provided
that
the
following
conditions
are
met
:
*
Redistributions
of
source
code
must
retain
the
above
copyright
notice
,
this
list
of
conditions
and
the
following
disclaimer
.
*
Redistributions
in
binary
form
must
reproduce
the
above
copyright
notice
,
this
list
of
conditions
and
the
following
disclaimer
in
the
documentation
and
/
or
other
materials
provided
with
the
distribution
.
*
Neither
the
name
of
Google
Inc
.
nor
the
names
of
its
contributors
may
be
used
to
endorse
or
promote
products
derived
from
this
software
without
specific
prior
written
permission
.
THIS
SOFTWARE
IS
PROVIDED
BY
THE
COPYRIGHT
HOLDERS
AND
CONTRIBUTORS
"AS IS"
AND
ANY
EXPRESS
OR
IMPLIED
WARRANTIES
,
INCLUDING
,
BUT
NOT
LIMITED
TO
,
THE
IMPLIED
WARRANTIES
OF
MERCHANTABILITY
AND
FITNESS
FOR
A
PARTICULAR
PURPOSE
ARE
DISCLAIMED
.
IN
NO
EVENT
SHALL
THE
COPYRIGHT
OWNER
OR
CONTRIBUTORS
BE
LIABLE
FOR
ANY
DIRECT
,
INDIRECT
,
INCIDENTAL
,
SPECIAL
,
EXEMPLARY
,
OR
CONSEQUENTIAL
DAMAGES
(
INCLUDING
,
BUT
NOT
LIMITED
TO
,
PROCUREMENT
OF
SUBSTITUTE
GOODS
OR
SERVICES
;
LOSS
OF
USE
,
DATA
,
OR
PROFITS
;
OR
BUSINESS
INTERRUPTION
)
HOWEVER
CAUSED
AND
ON
ANY
THEORY
OF
LIABILITY
,
WHETHER
IN
CONTRACT
,
STRICT
LIABILITY
,
OR
TORT
(
INCLUDING
NEGLIGENCE
OR
OTHERWISE
)
ARISING
IN
ANY
WAY
OUT
OF
THE
USE
OF
THIS
SOFTWARE
,
EVEN
IF
ADVISED
OF
THE
POSSIBILITY
OF
SUCH
DAMAGE
.
=
vendor
/
golang
.
org
/
x
/
net
/
LICENSE
5
d4950ecb7b26d2c5e4e7b4e0dd74707
-
================================================================================
================================================================================
=
vendor
/
golang
.
org
/
x
/
net
/
proxy
licensed
under
:
=
Copyright
(
c
)
2009
The
Go
Authors
.
All
rights
reserved
.
vendor/golang.org/x/net/context/context.go
View file @
e5ed62e8
...
...
@@ -36,12 +36,7 @@
// Contexts.
package
context
import
(
"errors"
"fmt"
"sync"
"time"
)
import
"time"
// A Context carries a deadline, a cancelation signal, and other values across
// API boundaries.
...
...
@@ -66,7 +61,7 @@ type Context interface {
//
// // Stream generates values with DoSomething and sends them to out
// // until DoSomething returns an error or ctx.Done is closed.
// func Stream(ctx context.Context, out
<-chan
Value) error {
// func Stream(ctx context.Context, out
chan<-
Value) error {
// for {
// v, err := DoSomething(ctx)
// if err != nil {
...
...
@@ -138,48 +133,6 @@ type Context interface {
Value
(
key
interface
{})
interface
{}
}
// Canceled is the error returned by Context.Err when the context is canceled.
var
Canceled
=
errors
.
New
(
"context canceled"
)
// DeadlineExceeded is the error returned by Context.Err when the context's
// deadline passes.
var
DeadlineExceeded
=
errors
.
New
(
"context deadline exceeded"
)
// An emptyCtx is never canceled, has no values, and has no deadline. It is not
// struct{}, since vars of this type must have distinct addresses.
type
emptyCtx
int
func
(
*
emptyCtx
)
Deadline
()
(
deadline
time
.
Time
,
ok
bool
)
{
return
}
func
(
*
emptyCtx
)
Done
()
<-
chan
struct
{}
{
return
nil
}
func
(
*
emptyCtx
)
Err
()
error
{
return
nil
}
func
(
*
emptyCtx
)
Value
(
key
interface
{})
interface
{}
{
return
nil
}
func
(
e
*
emptyCtx
)
String
()
string
{
switch
e
{
case
background
:
return
"context.Background"
case
todo
:
return
"context.TODO"
}
return
"unknown empty Context"
}
var
(
background
=
new
(
emptyCtx
)
todo
=
new
(
emptyCtx
)
)
// Background returns a non-nil, empty Context. It is never canceled, has no
// values, and has no deadline. It is typically used by the main function,
// initialization, and tests, and as the top-level Context for incoming
...
...
@@ -201,247 +154,3 @@ func TODO() Context {
// A CancelFunc does not wait for the work to stop.
// After the first call, subsequent calls to a CancelFunc do nothing.
type
CancelFunc
func
()
// WithCancel returns a copy of parent with a new Done channel. The returned
// context's Done channel is closed when the returned cancel function is called
// or when the parent context's Done channel is closed, whichever happens first.
//
// Canceling this context releases resources associated with it, so code should
// call cancel as soon as the operations running in this Context complete.
func
WithCancel
(
parent
Context
)
(
ctx
Context
,
cancel
CancelFunc
)
{
c
:=
newCancelCtx
(
parent
)
propagateCancel
(
parent
,
&
c
)
return
&
c
,
func
()
{
c
.
cancel
(
true
,
Canceled
)
}
}
// newCancelCtx returns an initialized cancelCtx.
func
newCancelCtx
(
parent
Context
)
cancelCtx
{
return
cancelCtx
{
Context
:
parent
,
done
:
make
(
chan
struct
{}),
}
}
// propagateCancel arranges for child to be canceled when parent is.
func
propagateCancel
(
parent
Context
,
child
canceler
)
{
if
parent
.
Done
()
==
nil
{
return
// parent is never canceled
}
if
p
,
ok
:=
parentCancelCtx
(
parent
);
ok
{
p
.
mu
.
Lock
()
if
p
.
err
!=
nil
{
// parent has already been canceled
child
.
cancel
(
false
,
p
.
err
)
}
else
{
if
p
.
children
==
nil
{
p
.
children
=
make
(
map
[
canceler
]
bool
)
}
p
.
children
[
child
]
=
true
}
p
.
mu
.
Unlock
()
}
else
{
go
func
()
{
select
{
case
<-
parent
.
Done
()
:
child
.
cancel
(
false
,
parent
.
Err
())
case
<-
child
.
Done
()
:
}
}()
}
}
// parentCancelCtx follows a chain of parent references until it finds a
// *cancelCtx. This function understands how each of the concrete types in this
// package represents its parent.
func
parentCancelCtx
(
parent
Context
)
(
*
cancelCtx
,
bool
)
{
for
{
switch
c
:=
parent
.
(
type
)
{
case
*
cancelCtx
:
return
c
,
true
case
*
timerCtx
:
return
&
c
.
cancelCtx
,
true
case
*
valueCtx
:
parent
=
c
.
Context
default
:
return
nil
,
false
}
}
}
// removeChild removes a context from its parent.
func
removeChild
(
parent
Context
,
child
canceler
)
{
p
,
ok
:=
parentCancelCtx
(
parent
)
if
!
ok
{
return
}
p
.
mu
.
Lock
()
if
p
.
children
!=
nil
{
delete
(
p
.
children
,
child
)
}
p
.
mu
.
Unlock
()
}
// A canceler is a context type that can be canceled directly. The
// implementations are *cancelCtx and *timerCtx.
type
canceler
interface
{
cancel
(
removeFromParent
bool
,
err
error
)
Done
()
<-
chan
struct
{}
}
// A cancelCtx can be canceled. When canceled, it also cancels any children
// that implement canceler.
type
cancelCtx
struct
{
Context
done
chan
struct
{}
// closed by the first cancel call.
mu
sync
.
Mutex
children
map
[
canceler
]
bool
// set to nil by the first cancel call
err
error
// set to non-nil by the first cancel call
}
func
(
c
*
cancelCtx
)
Done
()
<-
chan
struct
{}
{
return
c
.
done
}
func
(
c
*
cancelCtx
)
Err
()
error
{
c
.
mu
.
Lock
()
defer
c
.
mu
.
Unlock
()
return
c
.
err
}
func
(
c
*
cancelCtx
)
String
()
string
{
return
fmt
.
Sprintf
(
"%v.WithCancel"
,
c
.
Context
)
}
// cancel closes c.done, cancels each of c's children, and, if
// removeFromParent is true, removes c from its parent's children.
func
(
c
*
cancelCtx
)
cancel
(
removeFromParent
bool
,
err
error
)
{
if
err
==
nil
{
panic
(
"context: internal error: missing cancel error"
)
}
c
.
mu
.
Lock
()
if
c
.
err
!=
nil
{
c
.
mu
.
Unlock
()
return
// already canceled
}
c
.
err
=
err
close
(
c
.
done
)
for
child
:=
range
c
.
children
{
// NOTE: acquiring the child's lock while holding parent's lock.
child
.
cancel
(
false
,
err
)
}
c
.
children
=
nil
c
.
mu
.
Unlock
()
if
removeFromParent
{
removeChild
(
c
.
Context
,
c
)
}
}
// WithDeadline returns a copy of the parent context with the deadline adjusted
// to be no later than d. If the parent's deadline is already earlier than d,
// WithDeadline(parent, d) is semantically equivalent to parent. The returned
// context's Done channel is closed when the deadline expires, when the returned
// cancel function is called, or when the parent context's Done channel is
// closed, whichever happens first.
//
// Canceling this context releases resources associated with it, so code should
// call cancel as soon as the operations running in this Context complete.
func
WithDeadline
(
parent
Context
,
deadline
time
.
Time
)
(
Context
,
CancelFunc
)
{
if
cur
,
ok
:=
parent
.
Deadline
();
ok
&&
cur
.
Before
(
deadline
)
{
// The current deadline is already sooner than the new one.
return
WithCancel
(
parent
)
}
c
:=
&
timerCtx
{
cancelCtx
:
newCancelCtx
(
parent
),
deadline
:
deadline
,
}
propagateCancel
(
parent
,
c
)
d
:=
deadline
.
Sub
(
time
.
Now
())
if
d
<=
0
{
c
.
cancel
(
true
,
DeadlineExceeded
)
// deadline has already passed
return
c
,
func
()
{
c
.
cancel
(
true
,
Canceled
)
}
}
c
.
mu
.
Lock
()
defer
c
.
mu
.
Unlock
()
if
c
.
err
==
nil
{
c
.
timer
=
time
.
AfterFunc
(
d
,
func
()
{
c
.
cancel
(
true
,
DeadlineExceeded
)
})
}
return
c
,
func
()
{
c
.
cancel
(
true
,
Canceled
)
}
}
// A timerCtx carries a timer and a deadline. It embeds a cancelCtx to
// implement Done and Err. It implements cancel by stopping its timer then
// delegating to cancelCtx.cancel.
type
timerCtx
struct
{
cancelCtx
timer
*
time
.
Timer
// Under cancelCtx.mu.
deadline
time
.
Time
}
func
(
c
*
timerCtx
)
Deadline
()
(
deadline
time
.
Time
,
ok
bool
)
{
return
c
.
deadline
,
true
}
func
(
c
*
timerCtx
)
String
()
string
{
return
fmt
.
Sprintf
(
"%v.WithDeadline(%s [%s])"
,
c
.
cancelCtx
.
Context
,
c
.
deadline
,
c
.
deadline
.
Sub
(
time
.
Now
()))
}
func
(
c
*
timerCtx
)
cancel
(
removeFromParent
bool
,
err
error
)
{
c
.
cancelCtx
.
cancel
(
false
,
err
)
if
removeFromParent
{
// Remove this timerCtx from its parent cancelCtx's children.
removeChild
(
c
.
cancelCtx
.
Context
,
c
)
}
c
.
mu
.
Lock
()
if
c
.
timer
!=
nil
{
c
.
timer
.
Stop
()
c
.
timer
=
nil
}
c
.
mu
.
Unlock
()
}
// WithTimeout returns WithDeadline(parent, time.Now().Add(timeout)).
//
// Canceling this context releases resources associated with it, so code should
// call cancel as soon as the operations running in this Context complete:
//
// func slowOperationWithTimeout(ctx context.Context) (Result, error) {
// ctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond)
// defer cancel() // releases resources if slowOperation completes before timeout elapses
// return slowOperation(ctx)
// }
func
WithTimeout
(
parent
Context
,
timeout
time
.
Duration
)
(
Context
,
CancelFunc
)
{
return
WithDeadline
(
parent
,
time
.
Now
()
.
Add
(
timeout
))
}
// WithValue returns a copy of parent in which the value associated with key is
// val.
//
// Use context Values only for request-scoped data that transits processes and
// APIs, not for passing optional parameters to functions.
func
WithValue
(
parent
Context
,
key
interface
{},
val
interface
{})
Context
{
return
&
valueCtx
{
parent
,
key
,
val
}
}
// A valueCtx carries a key-value pair. It implements Value for that key and
// delegates all other calls to the embedded Context.
type
valueCtx
struct
{
Context
key
,
val
interface
{}
}
func
(
c
*
valueCtx
)
String
()
string
{
return
fmt
.
Sprintf
(
"%v.WithValue(%#v, %#v)"
,
c
.
Context
,
c
.
key
,
c
.
val
)
}
func
(
c
*
valueCtx
)
Value
(
key
interface
{})
interface
{}
{
if
c
.
key
==
key
{
return
c
.
val
}
return
c
.
Context
.
Value
(
key
)
}
vendor/golang.org/x/net/context/ctxhttp/cancelreq.go
deleted
100644 → 0
View file @
6193335b
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build go1.5
package
ctxhttp
import
"net/http"
func
canceler
(
client
*
http
.
Client
,
req
*
http
.
Request
)
func
()
{
// TODO(djd): Respect any existing value of req.Cancel.
ch
:=
make
(
chan
struct
{})
req
.
Cancel
=
ch
return
func
()
{
close
(
ch
)
}
}
vendor/golang.org/x/net/context/ctxhttp/cancelreq_go14.go
deleted
100644 → 0
View file @
6193335b
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !go1.5
package
ctxhttp
import
"net/http"
type
requestCanceler
interface
{
CancelRequest
(
*
http
.
Request
)
}
func
canceler
(
client
*
http
.
Client
,
req
*
http
.
Request
)
func
()
{
rc
,
ok
:=
client
.
Transport
.
(
requestCanceler
)
if
!
ok
{
return
func
()
{}
}
return
func
()
{
rc
.
CancelRequest
(
req
)
}
}
vendor/golang.org/x/net/context/ctxhttp/ctxhttp.go
View file @
e5ed62e8
// Copyright 201
5
The Go Authors. All rights reserved.
// Copyright 201
6
The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build go1.7
// Package ctxhttp provides helper functions for performing context-aware HTTP requests.
package
ctxhttp
...
...
@@ -14,71 +16,18 @@ import (
"golang.org/x/net/context"
)
func
nop
()
{}
var
(
testHookContextDoneBeforeHeaders
=
nop
testHookDoReturned
=
nop
testHookDidBodyClose
=
nop
)
// Do sends an HTTP request with the provided http.Client and returns an HTTP response.
// Do sends an HTTP request with the provided http.Client and returns
// an HTTP response.
//
// If the client is nil, http.DefaultClient is used.
// If the context is canceled or times out, ctx.Err() will be returned.
//
// The provided ctx must be non-nil. If it is canceled or times out,
// ctx.Err() will be returned.
func
Do
(
ctx
context
.
Context
,
client
*
http
.
Client
,
req
*
http
.
Request
)
(
*
http
.
Response
,
error
)
{
if
client
==
nil
{
client
=
http
.
DefaultClient
}
// Request cancelation changed in Go 1.5, see cancelreq.go and cancelreq_go14.go.
cancel
:=
canceler
(
client
,
req
)
type
responseAndError
struct
{
resp
*
http
.
Response
err
error
}
result
:=
make
(
chan
responseAndError
,
1
)
go
func
()
{
resp
,
err
:=
client
.
Do
(
req
)
testHookDoReturned
()
result
<-
responseAndError
{
resp
,
err
}
}()
var
resp
*
http
.
Response
select
{
case
<-
ctx
.
Done
()
:
testHookContextDoneBeforeHeaders
()
cancel
()
// Clean up after the goroutine calling client.Do:
go
func
()
{
if
r
:=
<-
result
;
r
.
resp
!=
nil
{
testHookDidBodyClose
()
r
.
resp
.
Body
.
Close
()
}
}()
return
nil
,
ctx
.
Err
()
case
r
:=
<-
result
:
var
err
error
resp
,
err
=
r
.
resp
,
r
.
err
if
err
!=
nil
{
return
resp
,
err
}
}
c
:=
make
(
chan
struct
{})
go
func
()
{
select
{
case
<-
ctx
.
Done
()
:
cancel
()
case
<-
c
:
// The response's Body is closed.
}
}()
resp
.
Body
=
&
notifyingReader
{
resp
.
Body
,
c
}
return
resp
,
nil
return
client
.
Do
(
req
.
WithContext
(
ctx
))
}
// Get issues a GET request via the Do function.
...
...
@@ -113,28 +62,3 @@ func Post(ctx context.Context, client *http.Client, url string, bodyType string,
func
PostForm
(
ctx
context
.
Context
,
client
*
http
.
Client
,
url
string
,
data
url
.
Values
)
(
*
http
.
Response
,
error
)
{
return
Post
(
ctx
,
client
,
url
,
"application/x-www-form-urlencoded"
,
strings
.
NewReader
(
data
.
Encode
()))
}
// notifyingReader is an io.ReadCloser that closes the notify channel after
// Close is called or a Read fails on the underlying ReadCloser.
type
notifyingReader
struct
{
io
.
ReadCloser
notify
chan
<-
struct
{}
}
func
(
r
*
notifyingReader
)
Read
(
p
[]
byte
)
(
int
,
error
)
{
n
,
err
:=
r
.
ReadCloser
.
Read
(
p
)
if
err
!=
nil
&&
r
.
notify
!=
nil
{
close
(
r
.
notify
)
r
.
notify
=
nil
}
return
n
,
err
}
func
(
r
*
notifyingReader
)
Close
()
error
{
err
:=
r
.
ReadCloser
.
Close
()
if
r
.
notify
!=
nil
{
close
(
r
.
notify
)
r
.
notify
=
nil
}
return
err
}
vendor/golang.org/x/net/context/ctxhttp/ctxhttp_pre17.go
0 → 100644
View file @
e5ed62e8
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !go1.7
package
ctxhttp
import
(
"io"
"net/http"
"net/url"
"strings"
"golang.org/x/net/context"
)
func
nop
()
{}
var
(
testHookContextDoneBeforeHeaders
=
nop
testHookDoReturned
=
nop
testHookDidBodyClose
=
nop
)
// Do sends an HTTP request with the provided http.Client and returns an HTTP response.
// If the client is nil, http.DefaultClient is used.
// If the context is canceled or times out, ctx.Err() will be returned.
func
Do
(
ctx
context
.
Context
,
client
*
http
.
Client
,
req
*
http
.
Request
)
(
*
http
.
Response
,
error
)
{
if
client
==
nil
{
client
=
http
.
DefaultClient
}
// TODO(djd): Respect any existing value of req.Cancel.
cancel
:=
make
(
chan
struct
{})
req
.
Cancel
=
cancel
type
responseAndError
struct
{
resp
*
http
.
Response
err
error
}
result
:=
make
(
chan
responseAndError
,
1
)
// Make local copies of test hooks closed over by goroutines below.
// Prevents data races in tests.
testHookDoReturned
:=
testHookDoReturned
testHookDidBodyClose
:=
testHookDidBodyClose
go
func
()
{
resp
,
err
:=
client
.
Do
(
req
)
testHookDoReturned
()
result
<-
responseAndError
{
resp
,
err
}
}()
var
resp
*
http
.
Response
select
{
case
<-
ctx
.
Done
()
:
testHookContextDoneBeforeHeaders
()
close
(
cancel
)
// Clean up after the goroutine calling client.Do:
go
func
()
{
if
r
:=
<-
result
;
r
.
resp
!=
nil
{
testHookDidBodyClose
()
r
.
resp
.
Body
.
Close
()
}
}()
return
nil
,
ctx
.
Err
()
case
r
:=
<-
result
:
var
err
error
resp
,
err
=
r
.
resp
,
r
.
err
if
err
!=
nil
{
return
resp
,
err
}
}
c
:=
make
(
chan
struct
{})
go
func
()
{
select
{
case
<-
ctx
.
Done
()
:
close
(
cancel
)
case
<-
c
:
// The response's Body is closed.
}
}()
resp
.
Body
=
&
notifyingReader
{
resp
.
Body
,
c
}
return
resp
,
nil
}
// Get issues a GET request via the Do function.
func
Get
(
ctx
context
.
Context
,
client
*
http
.
Client
,
url
string
)
(
*
http
.
Response
,
error
)
{
req
,
err
:=
http
.
NewRequest
(
"GET"
,
url
,
nil
)
if
err
!=
nil
{
return
nil
,
err
}
return
Do
(
ctx
,
client
,
req
)
}
// Head issues a HEAD request via the Do function.
func
Head
(
ctx
context
.
Context
,
client
*
http
.
Client
,
url
string
)
(
*
http
.
Response
,
error
)
{
req
,
err
:=
http
.
NewRequest
(
"HEAD"
,
url
,
nil
)
if
err
!=
nil
{
return
nil
,
err
}
return
Do
(
ctx
,
client
,
req
)
}
// Post issues a POST request via the Do function.
func
Post
(
ctx
context
.
Context
,
client
*
http
.
Client
,
url
string
,
bodyType
string
,
body
io
.
Reader
)
(
*
http
.
Response
,
error
)
{
req
,
err
:=
http
.
NewRequest
(
"POST"
,
url
,
body
)
if
err
!=
nil
{
return
nil
,
err
}
req
.
Header
.
Set
(
"Content-Type"
,
bodyType
)
return
Do
(
ctx
,
client
,
req
)
}
// PostForm issues a POST request via the Do function.
func
PostForm
(
ctx
context
.
Context
,
client
*
http
.
Client
,
url
string
,
data
url
.
Values
)
(
*
http
.
Response
,
error
)
{
return
Post
(
ctx
,
client
,
url
,
"application/x-www-form-urlencoded"
,
strings
.
NewReader
(
data
.
Encode
()))
}
// notifyingReader is an io.ReadCloser that closes the notify channel after
// Close is called or a Read fails on the underlying ReadCloser.
type
notifyingReader
struct
{
io
.
ReadCloser
notify
chan
<-
struct
{}
}
func
(
r
*
notifyingReader
)
Read
(
p
[]
byte
)
(
int
,
error
)
{
n
,
err
:=
r
.
ReadCloser
.
Read
(
p
)
if
err
!=
nil
&&
r
.
notify
!=
nil
{
close
(
r
.
notify
)
r
.
notify
=
nil
}
return
n
,
err
}
func
(
r
*
notifyingReader
)
Close
()
error
{
err
:=
r
.
ReadCloser
.
Close
()
if
r
.
notify
!=
nil
{
close
(
r
.
notify
)
r
.
notify
=
nil
}
return
err
}
vendor/golang.org/x/net/context/go17.go
0 → 100644
View file @
e5ed62e8
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build go1.7
package
context
import
(
"context"
// standard library's context, as of Go 1.7
"time"
)
var
(
todo
=
context
.
TODO
()
background
=
context
.
Background
()
)
// Canceled is the error returned by Context.Err when the context is canceled.
var
Canceled
=
context
.
Canceled
// DeadlineExceeded is the error returned by Context.Err when the context's
// deadline passes.
var
DeadlineExceeded
=
context
.
DeadlineExceeded
// WithCancel returns a copy of parent with a new Done channel. The returned
// context's Done channel is closed when the returned cancel function is called
// or when the parent context's Done channel is closed, whichever happens first.
//
// Canceling this context releases resources associated with it, so code should
// call cancel as soon as the operations running in this Context complete.
func
WithCancel
(
parent
Context
)
(
ctx
Context
,
cancel
CancelFunc
)
{
ctx
,
f
:=
context
.
WithCancel
(
parent
)
return
ctx
,
CancelFunc
(
f
)
}
// WithDeadline returns a copy of the parent context with the deadline adjusted
// to be no later than d. If the parent's deadline is already earlier than d,
// WithDeadline(parent, d) is semantically equivalent to parent. The returned
// context's Done channel is closed when the deadline expires, when the returned
// cancel function is called, or when the parent context's Done channel is
// closed, whichever happens first.
//
// Canceling this context releases resources associated with it, so code should
// call cancel as soon as the operations running in this Context complete.
func
WithDeadline
(
parent
Context
,
deadline
time
.
Time
)
(
Context
,
CancelFunc
)
{
ctx
,
f
:=
context
.
WithDeadline
(
parent
,
deadline
)
return
ctx
,
CancelFunc
(
f
)
}
// WithTimeout returns WithDeadline(parent, time.Now().Add(timeout)).
//
// Canceling this context releases resources associated with it, so code should
// call cancel as soon as the operations running in this Context complete:
//
// func slowOperationWithTimeout(ctx context.Context) (Result, error) {
// ctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond)
// defer cancel() // releases resources if slowOperation completes before timeout elapses
// return slowOperation(ctx)
// }
func
WithTimeout
(
parent
Context
,
timeout
time
.
Duration
)
(
Context
,
CancelFunc
)
{
return
WithDeadline
(
parent
,
time
.
Now
()
.
Add
(
timeout
))
}
// WithValue returns a copy of parent in which the value associated with key is
// val.
//
// Use context Values only for request-scoped data that transits processes and
// APIs, not for passing optional parameters to functions.
func
WithValue
(
parent
Context
,
key
interface
{},
val
interface
{})
Context
{
return
context
.
WithValue
(
parent
,
key
,
val
)
}
vendor/golang.org/x/net/context/pre_go17.go
0 → 100644
View file @
e5ed62e8
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !go1.7
package
context
import
(
"errors"
"fmt"
"sync"
"time"
)
// An emptyCtx is never canceled, has no values, and has no deadline. It is not
// struct{}, since vars of this type must have distinct addresses.
type
emptyCtx
int
func
(
*
emptyCtx
)
Deadline
()
(
deadline
time
.
Time
,
ok
bool
)
{
return
}
func
(
*
emptyCtx
)
Done
()
<-
chan
struct
{}
{
return
nil
}
func
(
*
emptyCtx
)
Err
()
error
{
return
nil
}
func
(
*
emptyCtx
)
Value
(
key
interface
{})
interface
{}
{
return
nil
}
func
(
e
*
emptyCtx
)
String
()
string
{
switch
e
{
case
background
:
return
"context.Background"
case
todo
:
return
"context.TODO"
}
return
"unknown empty Context"
}
var
(
background
=
new
(
emptyCtx
)
todo
=
new
(
emptyCtx
)
)
// Canceled is the error returned by Context.Err when the context is canceled.
var
Canceled
=
errors
.
New
(
"context canceled"
)
// DeadlineExceeded is the error returned by Context.Err when the context's
// deadline passes.
var
DeadlineExceeded
=
errors
.
New
(
"context deadline exceeded"
)
// WithCancel returns a copy of parent with a new Done channel. The returned
// context's Done channel is closed when the returned cancel function is called
// or when the parent context's Done channel is closed, whichever happens first.
//
// Canceling this context releases resources associated with it, so code should
// call cancel as soon as the operations running in this Context complete.
func
WithCancel
(
parent
Context
)
(
ctx
Context
,
cancel
CancelFunc
)
{
c
:=
newCancelCtx
(
parent
)
propagateCancel
(
parent
,
c
)
return
c
,
func
()
{
c
.
cancel
(
true
,
Canceled
)
}
}
// newCancelCtx returns an initialized cancelCtx.
func
newCancelCtx
(
parent
Context
)
*
cancelCtx
{
return
&
cancelCtx
{
Context
:
parent
,
done
:
make
(
chan
struct
{}),
}
}
// propagateCancel arranges for child to be canceled when parent is.
func
propagateCancel
(
parent
Context
,
child
canceler
)
{
if
parent
.
Done
()
==
nil
{
return
// parent is never canceled
}
if
p
,
ok
:=
parentCancelCtx
(
parent
);
ok
{
p
.
mu
.
Lock
()
if
p
.
err
!=
nil
{
// parent has already been canceled
child
.
cancel
(
false
,
p
.
err
)
}
else
{
if
p
.
children
==
nil
{
p
.
children
=
make
(
map
[
canceler
]
bool
)
}
p
.
children
[
child
]
=
true
}
p
.
mu
.
Unlock
()
}
else
{
go
func
()
{
select
{
case
<-
parent
.
Done
()
:
child
.
cancel
(
false
,
parent
.
Err
())
case
<-
child
.
Done
()
:
}
}()
}
}
// parentCancelCtx follows a chain of parent references until it finds a
// *cancelCtx. This function understands how each of the concrete types in this
// package represents its parent.
func
parentCancelCtx
(
parent
Context
)
(
*
cancelCtx
,
bool
)
{
for
{
switch
c
:=
parent
.
(
type
)
{
case
*
cancelCtx
:
return
c
,
true
case
*
timerCtx
:
return
c
.
cancelCtx
,
true
case
*
valueCtx
:
parent
=
c
.
Context
default
:
return
nil
,
false
}
}
}
// removeChild removes a context from its parent.
func
removeChild
(
parent
Context
,
child
canceler
)
{
p
,
ok
:=
parentCancelCtx
(
parent
)
if
!
ok
{
return
}
p
.
mu
.
Lock
()
if
p
.
children
!=
nil
{
delete
(
p
.
children
,
child
)
}
p
.
mu
.
Unlock
()
}
// A canceler is a context type that can be canceled directly. The
// implementations are *cancelCtx and *timerCtx.
type
canceler
interface
{
cancel
(
removeFromParent
bool
,
err
error
)
Done
()
<-
chan
struct
{}
}
// A cancelCtx can be canceled. When canceled, it also cancels any children
// that implement canceler.
type
cancelCtx
struct
{
Context
done
chan
struct
{}
// closed by the first cancel call.
mu
sync
.
Mutex
children
map
[
canceler
]
bool
// set to nil by the first cancel call
err
error
// set to non-nil by the first cancel call
}
func
(
c
*
cancelCtx
)
Done
()
<-
chan
struct
{}
{
return
c
.
done
}
func
(
c
*
cancelCtx
)
Err
()
error
{
c
.
mu
.
Lock
()
defer
c
.
mu
.
Unlock
()
return
c
.
err
}
func
(
c
*
cancelCtx
)
String
()
string
{
return
fmt
.
Sprintf
(
"%v.WithCancel"
,
c
.
Context
)
}
// cancel closes c.done, cancels each of c's children, and, if
// removeFromParent is true, removes c from its parent's children.
func
(
c
*
cancelCtx
)
cancel
(
removeFromParent
bool
,
err
error
)
{
if
err
==
nil
{
panic
(
"context: internal error: missing cancel error"
)
}
c
.
mu
.
Lock
()
if
c
.
err
!=
nil
{
c
.
mu
.
Unlock
()
return
// already canceled
}
c
.
err
=
err
close
(
c
.
done
)
for
child
:=
range
c
.
children
{
// NOTE: acquiring the child's lock while holding parent's lock.
child
.
cancel
(
false
,
err
)
}
c
.
children
=
nil
c
.
mu
.
Unlock
()
if
removeFromParent
{
removeChild
(
c
.
Context
,
c
)
}
}
// WithDeadline returns a copy of the parent context with the deadline adjusted
// to be no later than d. If the parent's deadline is already earlier than d,
// WithDeadline(parent, d) is semantically equivalent to parent. The returned
// context's Done channel is closed when the deadline expires, when the returned
// cancel function is called, or when the parent context's Done channel is
// closed, whichever happens first.
//
// Canceling this context releases resources associated with it, so code should
// call cancel as soon as the operations running in this Context complete.
func
WithDeadline
(
parent
Context
,
deadline
time
.
Time
)
(
Context
,
CancelFunc
)
{
if
cur
,
ok
:=
parent
.
Deadline
();
ok
&&
cur
.
Before
(
deadline
)
{
// The current deadline is already sooner than the new one.
return
WithCancel
(
parent
)
}
c
:=
&
timerCtx
{
cancelCtx
:
newCancelCtx
(
parent
),
deadline
:
deadline
,
}
propagateCancel
(
parent
,
c
)
d
:=
deadline
.
Sub
(
time
.
Now
())
if
d
<=
0
{
c
.
cancel
(
true
,
DeadlineExceeded
)
// deadline has already passed
return
c
,
func
()
{
c
.
cancel
(
true
,
Canceled
)
}
}
c
.
mu
.
Lock
()
defer
c
.
mu
.
Unlock
()
if
c
.
err
==
nil
{
c
.
timer
=
time
.
AfterFunc
(
d
,
func
()
{
c
.
cancel
(
true
,
DeadlineExceeded
)
})
}
return
c
,
func
()
{
c
.
cancel
(
true
,
Canceled
)
}
}
// A timerCtx carries a timer and a deadline. It embeds a cancelCtx to
// implement Done and Err. It implements cancel by stopping its timer then
// delegating to cancelCtx.cancel.
type
timerCtx
struct
{
*
cancelCtx
timer
*
time
.
Timer
// Under cancelCtx.mu.
deadline
time
.
Time
}
func
(
c
*
timerCtx
)
Deadline
()
(
deadline
time
.
Time
,
ok
bool
)
{
return
c
.
deadline
,
true
}
func
(
c
*
timerCtx
)
String
()
string
{
return
fmt
.
Sprintf
(
"%v.WithDeadline(%s [%s])"
,
c
.
cancelCtx
.
Context
,
c
.
deadline
,
c
.
deadline
.
Sub
(
time
.
Now
()))
}
func
(
c
*
timerCtx
)
cancel
(
removeFromParent
bool
,
err
error
)
{
c
.
cancelCtx
.
cancel
(
false
,
err
)
if
removeFromParent
{
// Remove this timerCtx from its parent cancelCtx's children.
removeChild
(
c
.
cancelCtx
.
Context
,
c
)
}
c
.
mu
.
Lock
()
if
c
.
timer
!=
nil
{
c
.
timer
.
Stop
()
c
.
timer
=
nil
}
c
.
mu
.
Unlock
()
}
// WithTimeout returns WithDeadline(parent, time.Now().Add(timeout)).
//
// Canceling this context releases resources associated with it, so code should
// call cancel as soon as the operations running in this Context complete:
//
// func slowOperationWithTimeout(ctx context.Context) (Result, error) {
// ctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond)
// defer cancel() // releases resources if slowOperation completes before timeout elapses
// return slowOperation(ctx)
// }
func
WithTimeout
(
parent
Context
,
timeout
time
.
Duration
)
(
Context
,
CancelFunc
)
{
return
WithDeadline
(
parent
,
time
.
Now
()
.
Add
(
timeout
))
}
// WithValue returns a copy of parent in which the value associated with key is
// val.
//
// Use context Values only for request-scoped data that transits processes and
// APIs, not for passing optional parameters to functions.
func
WithValue
(
parent
Context
,
key
interface
{},
val
interface
{})
Context
{
return
&
valueCtx
{
parent
,
key
,
val
}
}
// A valueCtx carries a key-value pair. It implements Value for that key and
// delegates all other calls to the embedded Context.
type
valueCtx
struct
{
Context
key
,
val
interface
{}
}
func
(
c
*
valueCtx
)
String
()
string
{
return
fmt
.
Sprintf
(
"%v.WithValue(%#v, %#v)"
,
c
.
Context
,
c
.
key
,
c
.
val
)
}
func
(
c
*
valueCtx
)
Value
(
key
interface
{})
interface
{}
{
if
c
.
key
==
key
{
return
c
.
val
}
return
c
.
Context
.
Value
(
key
)
}
vendor/golang.org/x/net/http2/client_conn_pool.go
View file @
e5ed62e8
...
...
@@ -18,6 +18,18 @@ type ClientConnPool interface {
MarkDead
(
*
ClientConn
)
}
// clientConnPoolIdleCloser is the interface implemented by ClientConnPool
// implementations which can close their idle connections.
type
clientConnPoolIdleCloser
interface
{
ClientConnPool
closeIdleConnections
()
}
var
(
_
clientConnPoolIdleCloser
=
(
*
clientConnPool
)(
nil
)
_
clientConnPoolIdleCloser
=
noDialClientConnPool
{}
)
// TODO: use singleflight for dialing and addConnCalls?
type
clientConnPool
struct
{
t
*
Transport
...
...
@@ -40,7 +52,16 @@ const (
noDialOnMiss
=
false
)
func
(
p
*
clientConnPool
)
getClientConn
(
_
*
http
.
Request
,
addr
string
,
dialOnMiss
bool
)
(
*
ClientConn
,
error
)
{
func
(
p
*
clientConnPool
)
getClientConn
(
req
*
http
.
Request
,
addr
string
,
dialOnMiss
bool
)
(
*
ClientConn
,
error
)
{
if
req
.
Close
&&
dialOnMiss
{
// It gets its own connection.
cc
,
err
:=
p
.
t
.
dialClientConn
(
addr
)
if
err
!=
nil
{
return
nil
,
err
}
cc
.
singleUse
=
true
return
cc
,
nil
}
p
.
mu
.
Lock
()
for
_
,
cc
:=
range
p
.
conns
[
addr
]
{
if
cc
.
CanTakeNewRequest
()
{
...
...
@@ -223,3 +244,12 @@ func filterOutClientConn(in []*ClientConn, exclude *ClientConn) []*ClientConn {
}
return
out
}
// noDialClientConnPool is an implementation of http2.ClientConnPool
// which never dials. We let the HTTP/1.1 client dial and use its TLS
// connection instead.
type
noDialClientConnPool
struct
{
*
clientConnPool
}
func
(
p
noDialClientConnPool
)
GetClientConn
(
req
*
http
.
Request
,
addr
string
)
(
*
ClientConn
,
error
)
{
return
p
.
getClientConn
(
req
,
addr
,
noDialOnMiss
)
}
vendor/golang.org/x/net/http2/configure_transport.go
View file @
e5ed62e8
...
...
@@ -32,7 +32,7 @@ func configureTransport(t1 *http.Transport) (*Transport, error) {
t1
.
TLSClientConfig
.
NextProtos
=
append
(
t1
.
TLSClientConfig
.
NextProtos
,
"http/1.1"
)
}
upgradeFn
:=
func
(
authority
string
,
c
*
tls
.
Conn
)
http
.
RoundTripper
{
addr
:=
authorityAddr
(
authority
)
addr
:=
authorityAddr
(
"https"
,
authority
)
if
used
,
err
:=
connPool
.
addConnIfNeeded
(
addr
,
t2
,
c
);
err
!=
nil
{
go
c
.
Close
()
return
erringRoundTripper
{
err
}
...
...
@@ -67,15 +67,6 @@ func registerHTTPSProtocol(t *http.Transport, rt http.RoundTripper) (err error)
return
nil
}
// noDialClientConnPool is an implementation of http2.ClientConnPool
// which never dials. We let the HTTP/1.1 client dial and use its TLS
// connection instead.
type
noDialClientConnPool
struct
{
*
clientConnPool
}
func
(
p
noDialClientConnPool
)
GetClientConn
(
req
*
http
.
Request
,
addr
string
)
(
*
ClientConn
,
error
)
{
return
p
.
getClientConn
(
req
,
addr
,
noDialOnMiss
)
}
// noDialH2RoundTripper is a RoundTripper which only tries to complete the request
// if there's already has a cached connection to the host.
type
noDialH2RoundTripper
struct
{
t
*
Transport
}
...
...
vendor/golang.org/x/net/http2/errors.go
View file @
e5ed62e8
...
...
@@ -4,7 +4,10 @@
package
http2
import
"fmt"
import
(
"errors"
"fmt"
)
// An ErrCode is an unsigned 32-bit error code as defined in the HTTP/2 spec.
type
ErrCode
uint32
...
...
@@ -88,3 +91,32 @@ type connError struct {
func
(
e
connError
)
Error
()
string
{
return
fmt
.
Sprintf
(
"http2: connection error: %v: %v"
,
e
.
Code
,
e
.
Reason
)
}
type
pseudoHeaderError
string
func
(
e
pseudoHeaderError
)
Error
()
string
{
return
fmt
.
Sprintf
(
"invalid pseudo-header %q"
,
string
(
e
))
}
type
duplicatePseudoHeaderError
string
func
(
e
duplicatePseudoHeaderError
)
Error
()
string
{
return
fmt
.
Sprintf
(
"duplicate pseudo-header %q"
,
string
(
e
))
}
type
headerFieldNameError
string
func
(
e
headerFieldNameError
)
Error
()
string
{
return
fmt
.
Sprintf
(
"invalid header field name %q"
,
string
(
e
))
}
type
headerFieldValueError
string
func
(
e
headerFieldValueError
)
Error
()
string
{
return
fmt
.
Sprintf
(
"invalid header field value %q"
,
string
(
e
))
}
var
(
errMixPseudoHeaderTypes
=
errors
.
New
(
"mix of request and response pseudo headers"
)
errPseudoAfterRegular
=
errors
.
New
(
"pseudo header field after regular"
)
)
vendor/golang.org/x/net/http2/frame.go
View file @
e5ed62e8
...
...
@@ -11,7 +11,11 @@ import (
"fmt"
"io"
"log"
"strings"
"sync"
"golang.org/x/net/http2/hpack"
"golang.org/x/net/lex/httplex"
)
const
frameHeaderLen
=
9
...
...
@@ -261,7 +265,7 @@ type Frame interface {
type
Framer
struct
{
r
io
.
Reader
lastFrame
Frame
err
Reason
string
err
Detail
error
// lastHeaderStream is non-zero if the last frame was an
// unfinished HEADERS/CONTINUATION.
...
...
@@ -293,8 +297,20 @@ type Framer struct {
// to return non-compliant frames or frame orders.
// This is for testing and permits using the Framer to test
// other HTTP/2 implementations' conformance to the spec.
// It is not compatible with ReadMetaHeaders.
AllowIllegalReads
bool
// ReadMetaHeaders if non-nil causes ReadFrame to merge
// HEADERS and CONTINUATION frames together and return
// MetaHeadersFrame instead.
ReadMetaHeaders
*
hpack
.
Decoder
// MaxHeaderListSize is the http2 MAX_HEADER_LIST_SIZE.
// It's used only if ReadMetaHeaders is set; 0 means a sane default
// (currently 16MB)
// If the limit is hit, MetaHeadersFrame.Truncated is set true.
MaxHeaderListSize
uint32
// TODO: track which type of frame & with which flags was sent
// last. Then return an error (unless AllowIllegalWrites) if
// we're in the middle of a header block and a
...
...
@@ -307,6 +323,13 @@ type Framer struct {
debugFramerBuf
*
bytes
.
Buffer
}
func
(
fr
*
Framer
)
maxHeaderListSize
()
uint32
{
if
fr
.
MaxHeaderListSize
==
0
{
return
16
<<
20
// sane default, per docs
}
return
fr
.
MaxHeaderListSize
}
func
(
f
*
Framer
)
startWrite
(
ftype
FrameType
,
flags
Flags
,
streamID
uint32
)
{
// Write the FrameHeader.
f
.
wbuf
=
append
(
f
.
wbuf
[
:
0
],
...
...
@@ -402,6 +425,17 @@ func (fr *Framer) SetMaxReadFrameSize(v uint32) {
fr
.
maxReadSize
=
v
}
// ErrorDetail returns a more detailed error of the last error
// returned by Framer.ReadFrame. For instance, if ReadFrame
// returns a StreamError with code PROTOCOL_ERROR, ErrorDetail
// will say exactly what was invalid. ErrorDetail is not guaranteed
// to return a non-nil value and like the rest of the http2 package,
// its return value is not protected by an API compatibility promise.
// ErrorDetail is reset after the next call to ReadFrame.
func
(
fr
*
Framer
)
ErrorDetail
()
error
{
return
fr
.
errDetail
}
// ErrFrameTooLarge is returned from Framer.ReadFrame when the peer
// sends a frame that is larger than declared with SetMaxReadFrameSize.
var
ErrFrameTooLarge
=
errors
.
New
(
"http2: frame too large"
)
...
...
@@ -420,9 +454,10 @@ func terminalReadFrameError(err error) bool {
//
// If the frame is larger than previously set with SetMaxReadFrameSize, the
// returned error is ErrFrameTooLarge. Other errors may be of type
// ConnectionError, StreamError, or anything else from
from
the underlying
// ConnectionError, StreamError, or anything else from the underlying
// reader.
func
(
fr
*
Framer
)
ReadFrame
()
(
Frame
,
error
)
{
fr
.
errDetail
=
nil
if
fr
.
lastFrame
!=
nil
{
fr
.
lastFrame
.
invalidate
()
}
...
...
@@ -450,6 +485,9 @@ func (fr *Framer) ReadFrame() (Frame, error) {
if
fr
.
logReads
{
log
.
Printf
(
"http2: Framer %p: read %v"
,
fr
,
summarizeFrame
(
f
))
}
if
fh
.
Type
==
FrameHeaders
&&
fr
.
ReadMetaHeaders
!=
nil
{
return
fr
.
readMetaFrame
(
f
.
(
*
HeadersFrame
))
}
return
f
,
nil
}
...
...
@@ -458,7 +496,7 @@ func (fr *Framer) ReadFrame() (Frame, error) {
// to the peer before hanging up on them. This might help others debug
// their implementations.
func
(
fr
*
Framer
)
connError
(
code
ErrCode
,
reason
string
)
error
{
fr
.
err
Reason
=
reason
fr
.
err
Detail
=
errors
.
New
(
reason
)
return
ConnectionError
(
code
)
}
...
...
@@ -553,7 +591,14 @@ func parseDataFrame(fh FrameHeader, payload []byte) (Frame, error) {
return
f
,
nil
}
var
errStreamID
=
errors
.
New
(
"invalid streamid"
)
var
(
errStreamID
=
errors
.
New
(
"invalid stream ID"
)
errDepStreamID
=
errors
.
New
(
"invalid dependent stream ID"
)
)
func
validStreamIDOrZero
(
streamID
uint32
)
bool
{
return
streamID
&
(
1
<<
31
)
==
0
}
func
validStreamID
(
streamID
uint32
)
bool
{
return
streamID
!=
0
&&
streamID
&
(
1
<<
31
)
==
0
...
...
@@ -940,8 +985,8 @@ func (f *Framer) WriteHeaders(p HeadersFrameParam) error {
}
if
!
p
.
Priority
.
IsZero
()
{
v
:=
p
.
Priority
.
StreamDep
if
!
validStreamID
(
v
)
&&
!
f
.
AllowIllegalWrites
{
return
err
ors
.
New
(
"invalid dependent stream id"
)
if
!
validStreamID
OrZero
(
v
)
&&
!
f
.
AllowIllegalWrites
{
return
err
DepStreamID
}
if
p
.
Priority
.
Exclusive
{
v
|=
1
<<
31
...
...
@@ -1009,6 +1054,9 @@ func (f *Framer) WritePriority(streamID uint32, p PriorityParam) error {
if
!
validStreamID
(
streamID
)
&&
!
f
.
AllowIllegalWrites
{
return
errStreamID
}
if
!
validStreamIDOrZero
(
p
.
StreamDep
)
{
return
errDepStreamID
}
f
.
startWrite
(
FramePriority
,
0
,
streamID
)
v
:=
p
.
StreamDep
if
p
.
Exclusive
{
...
...
@@ -1225,6 +1273,196 @@ type headersEnder interface {
HeadersEnded
()
bool
}
type
headersOrContinuation
interface
{
headersEnder
HeaderBlockFragment
()
[]
byte
}
// A MetaHeadersFrame is the representation of one HEADERS frame and
// zero or more contiguous CONTINUATION frames and the decoding of
// their HPACK-encoded contents.
//
// This type of frame does not appear on the wire and is only returned
// by the Framer when Framer.ReadMetaHeaders is set.
type
MetaHeadersFrame
struct
{
*
HeadersFrame
// Fields are the fields contained in the HEADERS and
// CONTINUATION frames. The underlying slice is owned by the
// Framer and must not be retained after the next call to
// ReadFrame.
//
// Fields are guaranteed to be in the correct http2 order and
// not have unknown pseudo header fields or invalid header
// field names or values. Required pseudo header fields may be
// missing, however. Use the MetaHeadersFrame.Pseudo accessor
// method access pseudo headers.
Fields
[]
hpack
.
HeaderField
// Truncated is whether the max header list size limit was hit
// and Fields is incomplete. The hpack decoder state is still
// valid, however.
Truncated
bool
}
// PseudoValue returns the given pseudo header field's value.
// The provided pseudo field should not contain the leading colon.
func
(
mh
*
MetaHeadersFrame
)
PseudoValue
(
pseudo
string
)
string
{
for
_
,
hf
:=
range
mh
.
Fields
{
if
!
hf
.
IsPseudo
()
{
return
""
}
if
hf
.
Name
[
1
:
]
==
pseudo
{
return
hf
.
Value
}
}
return
""
}
// RegularFields returns the regular (non-pseudo) header fields of mh.
// The caller does not own the returned slice.
func
(
mh
*
MetaHeadersFrame
)
RegularFields
()
[]
hpack
.
HeaderField
{
for
i
,
hf
:=
range
mh
.
Fields
{
if
!
hf
.
IsPseudo
()
{
return
mh
.
Fields
[
i
:
]
}
}
return
nil
}
// PseudoFields returns the pseudo header fields of mh.
// The caller does not own the returned slice.
func
(
mh
*
MetaHeadersFrame
)
PseudoFields
()
[]
hpack
.
HeaderField
{
for
i
,
hf
:=
range
mh
.
Fields
{
if
!
hf
.
IsPseudo
()
{
return
mh
.
Fields
[
:
i
]
}
}
return
mh
.
Fields
}
func
(
mh
*
MetaHeadersFrame
)
checkPseudos
()
error
{
var
isRequest
,
isResponse
bool
pf
:=
mh
.
PseudoFields
()
for
i
,
hf
:=
range
pf
{
switch
hf
.
Name
{
case
":method"
,
":path"
,
":scheme"
,
":authority"
:
isRequest
=
true
case
":status"
:
isResponse
=
true
default
:
return
pseudoHeaderError
(
hf
.
Name
)
}
// Check for duplicates.
// This would be a bad algorithm, but N is 4.
// And this doesn't allocate.
for
_
,
hf2
:=
range
pf
[
:
i
]
{
if
hf
.
Name
==
hf2
.
Name
{
return
duplicatePseudoHeaderError
(
hf
.
Name
)
}
}
}
if
isRequest
&&
isResponse
{
return
errMixPseudoHeaderTypes
}
return
nil
}
func
(
fr
*
Framer
)
maxHeaderStringLen
()
int
{
v
:=
fr
.
maxHeaderListSize
()
if
uint32
(
int
(
v
))
==
v
{
return
int
(
v
)
}
// They had a crazy big number for MaxHeaderBytes anyway,
// so give them unlimited header lengths:
return
0
}
// readMetaFrame returns 0 or more CONTINUATION frames from fr and
// merge them into into the provided hf and returns a MetaHeadersFrame
// with the decoded hpack values.
func
(
fr
*
Framer
)
readMetaFrame
(
hf
*
HeadersFrame
)
(
*
MetaHeadersFrame
,
error
)
{
if
fr
.
AllowIllegalReads
{
return
nil
,
errors
.
New
(
"illegal use of AllowIllegalReads with ReadMetaHeaders"
)
}
mh
:=
&
MetaHeadersFrame
{
HeadersFrame
:
hf
,
}
var
remainSize
=
fr
.
maxHeaderListSize
()
var
sawRegular
bool
var
invalid
error
// pseudo header field errors
hdec
:=
fr
.
ReadMetaHeaders
hdec
.
SetEmitEnabled
(
true
)
hdec
.
SetMaxStringLength
(
fr
.
maxHeaderStringLen
())
hdec
.
SetEmitFunc
(
func
(
hf
hpack
.
HeaderField
)
{
if
!
httplex
.
ValidHeaderFieldValue
(
hf
.
Value
)
{
invalid
=
headerFieldValueError
(
hf
.
Value
)
}
isPseudo
:=
strings
.
HasPrefix
(
hf
.
Name
,
":"
)
if
isPseudo
{
if
sawRegular
{
invalid
=
errPseudoAfterRegular
}
}
else
{
sawRegular
=
true
if
!
validWireHeaderFieldName
(
hf
.
Name
)
{
invalid
=
headerFieldNameError
(
hf
.
Name
)
}
}
if
invalid
!=
nil
{
hdec
.
SetEmitEnabled
(
false
)
return
}
size
:=
hf
.
Size
()
if
size
>
remainSize
{
hdec
.
SetEmitEnabled
(
false
)
mh
.
Truncated
=
true
return
}
remainSize
-=
size
mh
.
Fields
=
append
(
mh
.
Fields
,
hf
)
})
// Lose reference to MetaHeadersFrame:
defer
hdec
.
SetEmitFunc
(
func
(
hf
hpack
.
HeaderField
)
{})
var
hc
headersOrContinuation
=
hf
for
{
frag
:=
hc
.
HeaderBlockFragment
()
if
_
,
err
:=
hdec
.
Write
(
frag
);
err
!=
nil
{
return
nil
,
ConnectionError
(
ErrCodeCompression
)
}
if
hc
.
HeadersEnded
()
{
break
}
if
f
,
err
:=
fr
.
ReadFrame
();
err
!=
nil
{
return
nil
,
err
}
else
{
hc
=
f
.
(
*
ContinuationFrame
)
// guaranteed by checkFrameOrder
}
}
mh
.
HeadersFrame
.
headerFragBuf
=
nil
mh
.
HeadersFrame
.
invalidate
()
if
err
:=
hdec
.
Close
();
err
!=
nil
{
return
nil
,
ConnectionError
(
ErrCodeCompression
)
}
if
invalid
!=
nil
{
fr
.
errDetail
=
invalid
return
nil
,
StreamError
{
mh
.
StreamID
,
ErrCodeProtocol
}
}
if
err
:=
mh
.
checkPseudos
();
err
!=
nil
{
fr
.
errDetail
=
err
return
nil
,
StreamError
{
mh
.
StreamID
,
ErrCodeProtocol
}
}
return
mh
,
nil
}
func
summarizeFrame
(
f
Frame
)
string
{
var
buf
bytes
.
Buffer
f
.
Header
()
.
writeDebug
(
&
buf
)
...
...
vendor/golang.org/x/net/http2/go15.go
deleted
100644 → 0
View file @
6193335b
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build go1.5
package
http2
import
"net/http"
func
requestCancel
(
req
*
http
.
Request
)
<-
chan
struct
{}
{
return
req
.
Cancel
}
vendor/golang.org/x/net/http2/go16.go
0 → 100644
View file @
e5ed62e8
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build go1.6
package
http2
import
(
"crypto/tls"
"net/http"
"time"
)
func
transportExpectContinueTimeout
(
t1
*
http
.
Transport
)
time
.
Duration
{
return
t1
.
ExpectContinueTimeout
}
// isBadCipher reports whether the cipher is blacklisted by the HTTP/2 spec.
func
isBadCipher
(
cipher
uint16
)
bool
{
switch
cipher
{
case
tls
.
TLS_RSA_WITH_RC4_128_SHA
,
tls
.
TLS_RSA_WITH_3DES_EDE_CBC_SHA
,
tls
.
TLS_RSA_WITH_AES_128_CBC_SHA
,
tls
.
TLS_RSA_WITH_AES_256_CBC_SHA
,
tls
.
TLS_RSA_WITH_AES_128_GCM_SHA256
,
tls
.
TLS_RSA_WITH_AES_256_GCM_SHA384
,
tls
.
TLS_ECDHE_ECDSA_WITH_RC4_128_SHA
,
tls
.
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
,
tls
.
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
,
tls
.
TLS_ECDHE_RSA_WITH_RC4_128_SHA
,
tls
.
TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA
,
tls
.
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
,
tls
.
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
:
// Reject cipher suites from Appendix A.
// "This list includes those cipher suites that do not
// offer an ephemeral key exchange and those that are
// based on the TLS null, stream or block cipher type"
return
true
default
:
return
false
}
}
vendor/golang.org/x/net/http2/go17.go
0 → 100644
View file @
e5ed62e8
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build go1.7
package
http2
import
(
"context"
"net"
"net/http"
"net/http/httptrace"
"time"
)
type
contextContext
interface
{
context
.
Context
}
func
serverConnBaseContext
(
c
net
.
Conn
,
opts
*
ServeConnOpts
)
(
ctx
contextContext
,
cancel
func
())
{
ctx
,
cancel
=
context
.
WithCancel
(
context
.
Background
())
ctx
=
context
.
WithValue
(
ctx
,
http
.
LocalAddrContextKey
,
c
.
LocalAddr
())
if
hs
:=
opts
.
baseConfig
();
hs
!=
nil
{
ctx
=
context
.
WithValue
(
ctx
,
http
.
ServerContextKey
,
hs
)
}
return
}
func
contextWithCancel
(
ctx
contextContext
)
(
_
contextContext
,
cancel
func
())
{
return
context
.
WithCancel
(
ctx
)
}
func
requestWithContext
(
req
*
http
.
Request
,
ctx
contextContext
)
*
http
.
Request
{
return
req
.
WithContext
(
ctx
)
}
type
clientTrace
httptrace
.
ClientTrace
func
reqContext
(
r
*
http
.
Request
)
context
.
Context
{
return
r
.
Context
()
}
func
setResponseUncompressed
(
res
*
http
.
Response
)
{
res
.
Uncompressed
=
true
}
func
traceGotConn
(
req
*
http
.
Request
,
cc
*
ClientConn
)
{
trace
:=
httptrace
.
ContextClientTrace
(
req
.
Context
())
if
trace
==
nil
||
trace
.
GotConn
==
nil
{
return
}
ci
:=
httptrace
.
GotConnInfo
{
Conn
:
cc
.
tconn
}
cc
.
mu
.
Lock
()
ci
.
Reused
=
cc
.
nextStreamID
>
1
ci
.
WasIdle
=
len
(
cc
.
streams
)
==
0
&&
ci
.
Reused
if
ci
.
WasIdle
&&
!
cc
.
lastActive
.
IsZero
()
{
ci
.
IdleTime
=
time
.
Now
()
.
Sub
(
cc
.
lastActive
)
}
cc
.
mu
.
Unlock
()
trace
.
GotConn
(
ci
)
}
func
traceWroteHeaders
(
trace
*
clientTrace
)
{
if
trace
!=
nil
&&
trace
.
WroteHeaders
!=
nil
{
trace
.
WroteHeaders
()
}
}
func
traceGot100Continue
(
trace
*
clientTrace
)
{
if
trace
!=
nil
&&
trace
.
Got100Continue
!=
nil
{
trace
.
Got100Continue
()
}
}
func
traceWait100Continue
(
trace
*
clientTrace
)
{
if
trace
!=
nil
&&
trace
.
Wait100Continue
!=
nil
{
trace
.
Wait100Continue
()
}
}
func
traceWroteRequest
(
trace
*
clientTrace
,
err
error
)
{
if
trace
!=
nil
&&
trace
.
WroteRequest
!=
nil
{
trace
.
WroteRequest
(
httptrace
.
WroteRequestInfo
{
Err
:
err
})
}
}
func
traceFirstResponseByte
(
trace
*
clientTrace
)
{
if
trace
!=
nil
&&
trace
.
GotFirstResponseByte
!=
nil
{
trace
.
GotFirstResponseByte
()
}
}
func
requestTrace
(
req
*
http
.
Request
)
*
clientTrace
{
trace
:=
httptrace
.
ContextClientTrace
(
req
.
Context
())
return
(
*
clientTrace
)(
trace
)
}
vendor/golang.org/x/net/http2/hpack/encode.go
View file @
e5ed62e8
...
...
@@ -144,7 +144,7 @@ func (e *Encoder) SetMaxDynamicTableSizeLimit(v uint32) {
// shouldIndex reports whether f should be indexed.
func
(
e
*
Encoder
)
shouldIndex
(
f
HeaderField
)
bool
{
return
!
f
.
Sensitive
&&
f
.
s
ize
()
<=
e
.
dynTab
.
maxSize
return
!
f
.
Sensitive
&&
f
.
S
ize
()
<=
e
.
dynTab
.
maxSize
}
// appendIndexed appends index i, as encoded in "Indexed Header Field"
...
...
vendor/golang.org/x/net/http2/hpack/hpack.go
View file @
e5ed62e8
...
...
@@ -41,6 +41,14 @@ type HeaderField struct {
Sensitive
bool
}
// IsPseudo reports whether the header field is an http2 pseudo header.
// That is, it reports whether it starts with a colon.
// It is not otherwise guaranteed to be a valid pseudo header field,
// though.
func
(
hf
HeaderField
)
IsPseudo
()
bool
{
return
len
(
hf
.
Name
)
!=
0
&&
hf
.
Name
[
0
]
==
':'
}
func
(
hf
HeaderField
)
String
()
string
{
var
suffix
string
if
hf
.
Sensitive
{
...
...
@@ -49,7 +57,8 @@ func (hf HeaderField) String() string {
return
fmt
.
Sprintf
(
"header field %q = %q%s"
,
hf
.
Name
,
hf
.
Value
,
suffix
)
}
func
(
hf
*
HeaderField
)
size
()
uint32
{
// Size returns the size of an entry per RFC 7540 section 5.2.
func
(
hf
HeaderField
)
Size
()
uint32
{
// http://http2.github.io/http2-spec/compression.html#rfc.section.4.1
// "The size of the dynamic table is the sum of the size of
// its entries. The size of an entry is the sum of its name's
...
...
@@ -171,7 +180,7 @@ func (dt *dynamicTable) setMaxSize(v uint32) {
func
(
dt
*
dynamicTable
)
add
(
f
HeaderField
)
{
dt
.
ents
=
append
(
dt
.
ents
,
f
)
dt
.
size
+=
f
.
s
ize
()
dt
.
size
+=
f
.
S
ize
()
dt
.
evict
()
}
...
...
@@ -179,7 +188,7 @@ func (dt *dynamicTable) add(f HeaderField) {
func
(
dt
*
dynamicTable
)
evict
()
{
base
:=
dt
.
ents
// keep base pointer of slice
for
dt
.
size
>
dt
.
maxSize
{
dt
.
size
-=
dt
.
ents
[
0
]
.
s
ize
()
dt
.
size
-=
dt
.
ents
[
0
]
.
S
ize
()
dt
.
ents
=
dt
.
ents
[
1
:
]
}
...
...
vendor/golang.org/x/net/http2/hpack/huffman.go
View file @
e5ed62e8
...
...
@@ -48,12 +48,16 @@ var ErrInvalidHuffman = errors.New("hpack: invalid Huffman-encoded data")
// maxLen bytes will return ErrStringLength.
func
huffmanDecode
(
buf
*
bytes
.
Buffer
,
maxLen
int
,
v
[]
byte
)
error
{
n
:=
rootHuffmanNode
cur
,
nbits
:=
uint
(
0
),
uint8
(
0
)
// cur is the bit buffer that has not been fed into n.
// cbits is the number of low order bits in cur that are valid.
// sbits is the number of bits of the symbol prefix being decoded.
cur
,
cbits
,
sbits
:=
uint
(
0
),
uint8
(
0
),
uint8
(
0
)
for
_
,
b
:=
range
v
{
cur
=
cur
<<
8
|
uint
(
b
)
nbits
+=
8
for
nbits
>=
8
{
idx
:=
byte
(
cur
>>
(
nbits
-
8
))
cbits
+=
8
sbits
+=
8
for
cbits
>=
8
{
idx
:=
byte
(
cur
>>
(
cbits
-
8
))
n
=
n
.
children
[
idx
]
if
n
==
nil
{
return
ErrInvalidHuffman
...
...
@@ -63,22 +67,40 @@ func huffmanDecode(buf *bytes.Buffer, maxLen int, v []byte) error {
return
ErrStringLength
}
buf
.
WriteByte
(
n
.
sym
)
n
bits
-=
n
.
codeLen
c
bits
-=
n
.
codeLen
n
=
rootHuffmanNode
sbits
=
cbits
}
else
{
n
bits
-=
8
c
bits
-=
8
}
}
}
for
nbits
>
0
{
n
=
n
.
children
[
byte
(
cur
<<
(
8
-
nbits
))]
if
n
.
children
!=
nil
||
n
.
codeLen
>
nbits
{
for
cbits
>
0
{
n
=
n
.
children
[
byte
(
cur
<<
(
8
-
cbits
))]
if
n
==
nil
{
return
ErrInvalidHuffman
}
if
n
.
children
!=
nil
||
n
.
codeLen
>
cbits
{
break
}
if
maxLen
!=
0
&&
buf
.
Len
()
==
maxLen
{
return
ErrStringLength
}
buf
.
WriteByte
(
n
.
sym
)
n
bits
-=
n
.
codeLen
c
bits
-=
n
.
codeLen
n
=
rootHuffmanNode
sbits
=
cbits
}
if
sbits
>
7
{
// Either there was an incomplete symbol, or overlong padding.
// Both are decoding errors per RFC 7541 section 5.2.
return
ErrInvalidHuffman
}
if
mask
:=
uint
(
1
<<
cbits
-
1
);
cur
&
mask
!=
mask
{
// Trailing bits must be a prefix of EOS per RFC 7541 section 5.2.
return
ErrInvalidHuffman
}
return
nil
}
...
...
vendor/golang.org/x/net/http2/http2.go
View file @
e5ed62e8
...
...
@@ -23,9 +23,12 @@ import (
"io"
"net/http"
"os"
"sort"
"strconv"
"strings"
"sync"
"golang.org/x/net/lex/httplex"
)
var
(
...
...
@@ -165,57 +168,23 @@ var (
errInvalidHeaderFieldValue
=
errors
.
New
(
"http2: invalid header field value"
)
)
// validHeaderFieldName reports whether v is a valid header field name (key).
// RFC 7230 says:
// header-field = field-name ":" OWS field-value OWS
// field-name = token
// tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "." /
// "^" / "_" / "
// validWireHeaderFieldName reports whether v is a valid header field
// name (key). See httplex.ValidHeaderName for the base rules.
//
// Further, http2 says:
// "Just as in HTTP/1.x, header field names are strings of ASCII
// characters that are compared in a case-insensitive
// fashion. However, header field names MUST be converted to
// lowercase prior to their encoding in HTTP/2. "
func
validHeaderFieldName
(
v
string
)
bool
{
func
valid
Wire
HeaderFieldName
(
v
string
)
bool
{
if
len
(
v
)
==
0
{
return
false
}
for
_
,
r
:=
range
v
{
if
int
(
r
)
>=
len
(
isTokenTable
)
||
(
'A'
<=
r
&&
r
<=
'Z'
)
{
return
false
}
if
!
isTokenTable
[
byte
(
r
)]
{
if
!
httplex
.
IsTokenRune
(
r
)
{
return
false
}
}
return
true
}
// validHeaderFieldValue reports whether v is a valid header field value.
//
// RFC 7230 says:
// field-value = *( field-content / obs-fold )
// obj-fold = N/A to http2, and deprecated
// field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ]
// field-vchar = VCHAR / obs-text
// obs-text = %x80-FF
// VCHAR = "any visible [USASCII] character"
//
// http2 further says: "Similarly, HTTP/2 allows header field values
// that are not valid. While most of the values that can be encoded
// will not alter header field parsing, carriage return (CR, ASCII
// 0xd), line feed (LF, ASCII 0xa), and the zero character (NUL, ASCII
// 0x0) might be exploited by an attacker if they are translated
// verbatim. Any request or response that contains a character not
// permitted in a header field value MUST be treated as malformed
// (Section 8.1.2.6). Valid characters are defined by the
// field-content ABNF rule in Section 3.2 of [RFC7230]."
//
// This function does not (yet?) properly handle the rejection of
// strings that begin or end with SP or HTAB.
func
validHeaderFieldValue
(
v
string
)
bool
{
for
i
:=
0
;
i
<
len
(
v
);
i
++
{
if
b
:=
v
[
i
];
b
<
' '
&&
b
!=
'\t'
||
b
==
0x7f
{
if
'A'
<=
r
&&
r
<=
'Z'
{
return
false
}
}
...
...
@@ -320,7 +289,7 @@ func mustUint31(v int32) uint32 {
}
// bodyAllowedForStatus reports whether a given response status code
// permits a body. See RFC2616, section 4.4.
// permits a body. See RFC
2616, section 4.4.
func
bodyAllowedForStatus
(
status
int
)
bool
{
switch
{
case
status
>=
100
&&
status
<=
199
:
...
...
@@ -344,86 +313,39 @@ func (e *httpError) Temporary() bool { return true }
var
errTimeout
error
=
&
httpError
{
msg
:
"http2: timeout awaiting response headers"
,
timeout
:
true
}
var
isTokenTable
=
[
127
]
bool
{
'!'
:
true
,
'#'
:
true
,
'$'
:
true
,
'%'
:
true
,
'&'
:
true
,
'\'
'
:
true
,
'*'
:
true
,
'+'
:
true
,
'-'
:
true
,
'.'
:
true
,
'0'
:
true
,
'1'
:
true
,
'2'
:
true
,
'3'
:
true
,
'4'
:
true
,
'5'
:
true
,
'6'
:
true
,
'7'
:
true
,
'8'
:
true
,
'9'
:
true
,
'A'
:
true
,
'B'
:
true
,
'C'
:
true
,
'D'
:
true
,
'E'
:
true
,
'F'
:
true
,
'G'
:
true
,
'H'
:
true
,
'I'
:
true
,
'J'
:
true
,
'K'
:
true
,
'L'
:
true
,
'M'
:
true
,
'N'
:
true
,
'O'
:
true
,
'P'
:
true
,
'Q'
:
true
,
'R'
:
true
,
'S'
:
true
,
'T'
:
true
,
'U'
:
true
,
'W'
:
true
,
'V'
:
true
,
'X'
:
true
,
'Y'
:
true
,
'Z'
:
true
,
'^'
:
true
,
'_'
:
true
,
'`'
:
true
,
'a'
:
true
,
'b'
:
true
,
'c'
:
true
,
'd'
:
true
,
'e'
:
true
,
'f'
:
true
,
'g'
:
true
,
'h'
:
true
,
'i'
:
true
,
'j'
:
true
,
'k'
:
true
,
'l'
:
true
,
'm'
:
true
,
'n'
:
true
,
'o'
:
true
,
'p'
:
true
,
'q'
:
true
,
'r'
:
true
,
's'
:
true
,
't'
:
true
,
'u'
:
true
,
'v'
:
true
,
'w'
:
true
,
'x'
:
true
,
'y'
:
true
,
'z'
:
true
,
'|'
:
true
,
'~'
:
true
,
}
type
connectionStater
interface
{
ConnectionState
()
tls
.
ConnectionState
}
var
sorterPool
=
sync
.
Pool
{
New
:
func
()
interface
{}
{
return
new
(
sorter
)
}}
type
sorter
struct
{
v
[]
string
// owned by sorter
}
func
(
s
*
sorter
)
Len
()
int
{
return
len
(
s
.
v
)
}
func
(
s
*
sorter
)
Swap
(
i
,
j
int
)
{
s
.
v
[
i
],
s
.
v
[
j
]
=
s
.
v
[
j
],
s
.
v
[
i
]
}
func
(
s
*
sorter
)
Less
(
i
,
j
int
)
bool
{
return
s
.
v
[
i
]
<
s
.
v
[
j
]
}
// Keys returns the sorted keys of h.
//
// The returned slice is only valid until s used again or returned to
// its pool.
func
(
s
*
sorter
)
Keys
(
h
http
.
Header
)
[]
string
{
keys
:=
s
.
v
[
:
0
]
for
k
:=
range
h
{
keys
=
append
(
keys
,
k
)
}
s
.
v
=
keys
sort
.
Sort
(
s
)
return
keys
}
func
(
s
*
sorter
)
SortStrings
(
ss
[]
string
)
{
// Our sorter works on s.v, which sorter owners, so
// stash it away while we sort the user's buffer.
save
:=
s
.
v
s
.
v
=
ss
sort
.
Sort
(
s
)
s
.
v
=
save
}
vendor/golang.org/x/net/http2/not_go15.go
deleted
100644 → 0
View file @
6193335b
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !go1.5
package
http2
import
"net/http"
func
requestCancel
(
req
*
http
.
Request
)
<-
chan
struct
{}
{
return
nil
}
vendor/golang.org/x/net/http2/not_go16.go
View file @
e5ed62e8
...
...
@@ -6,8 +6,41 @@
package
http2
import
"net/http"
import
(
"crypto/tls"
"net/http"
"time"
)
func
configureTransport
(
t1
*
http
.
Transport
)
(
*
Transport
,
error
)
{
return
nil
,
errTransportVersion
}
func
transportExpectContinueTimeout
(
t1
*
http
.
Transport
)
time
.
Duration
{
return
0
}
// isBadCipher reports whether the cipher is blacklisted by the HTTP/2 spec.
func
isBadCipher
(
cipher
uint16
)
bool
{
switch
cipher
{
case
tls
.
TLS_RSA_WITH_RC4_128_SHA
,
tls
.
TLS_RSA_WITH_3DES_EDE_CBC_SHA
,
tls
.
TLS_RSA_WITH_AES_128_CBC_SHA
,
tls
.
TLS_RSA_WITH_AES_256_CBC_SHA
,
tls
.
TLS_ECDHE_ECDSA_WITH_RC4_128_SHA
,
tls
.
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
,
tls
.
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
,
tls
.
TLS_ECDHE_RSA_WITH_RC4_128_SHA
,
tls
.
TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA
,
tls
.
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
,
tls
.
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
:
// Reject cipher suites from Appendix A.
// "This list includes those cipher suites that do not
// offer an ephemeral key exchange and those that are
// based on the TLS null, stream or block cipher type"
return
true
default
:
return
false
}
}
vendor/golang.org/x/net/http2/not_go17.go
0 → 100644
View file @
e5ed62e8
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !go1.7
package
http2
import
(
"net"
"net/http"
)
type
contextContext
interface
{}
type
fakeContext
struct
{}
func
(
fakeContext
)
Done
()
<-
chan
struct
{}
{
return
nil
}
func
(
fakeContext
)
Err
()
error
{
panic
(
"should not be called"
)
}
func
reqContext
(
r
*
http
.
Request
)
fakeContext
{
return
fakeContext
{}
}
func
setResponseUncompressed
(
res
*
http
.
Response
)
{
// Nothing.
}
type
clientTrace
struct
{}
func
requestTrace
(
*
http
.
Request
)
*
clientTrace
{
return
nil
}
func
traceGotConn
(
*
http
.
Request
,
*
ClientConn
)
{}
func
traceFirstResponseByte
(
*
clientTrace
)
{}
func
traceWroteHeaders
(
*
clientTrace
)
{}
func
traceWroteRequest
(
*
clientTrace
,
error
)
{}
func
traceGot100Continue
(
trace
*
clientTrace
)
{}
func
traceWait100Continue
(
trace
*
clientTrace
)
{}
func
nop
()
{}
func
serverConnBaseContext
(
c
net
.
Conn
,
opts
*
ServeConnOpts
)
(
ctx
contextContext
,
cancel
func
())
{
return
nil
,
nop
}
func
contextWithCancel
(
ctx
contextContext
)
(
_
contextContext
,
cancel
func
())
{
return
ctx
,
nop
}
func
requestWithContext
(
req
*
http
.
Request
,
ctx
contextContext
)
*
http
.
Request
{
return
req
}
vendor/golang.org/x/net/http2/pipe.go
View file @
e5ed62e8
...
...
@@ -29,6 +29,12 @@ type pipeBuffer interface {
io
.
Reader
}
func
(
p
*
pipe
)
Len
()
int
{
p
.
mu
.
Lock
()
defer
p
.
mu
.
Unlock
()
return
p
.
b
.
Len
()
}
// Read waits until data is available and copies bytes
// from the buffer into p.
func
(
p
*
pipe
)
Read
(
d
[]
byte
)
(
n
int
,
err
error
)
{
...
...
vendor/golang.org/x/net/http2/server.go
View file @
e5ed62e8
...
...
@@ -51,7 +51,6 @@ import (
"os"
"reflect"
"runtime"
"sort"
"strconv"
"strings"
"sync"
...
...
@@ -251,10 +250,14 @@ func (o *ServeConnOpts) handler() http.Handler {
//
// The opts parameter is optional. If nil, default values are used.
func
(
s
*
Server
)
ServeConn
(
c
net
.
Conn
,
opts
*
ServeConnOpts
)
{
baseCtx
,
cancel
:=
serverConnBaseContext
(
c
,
opts
)
defer
cancel
()
sc
:=
&
serverConn
{
srv
:
s
,
hs
:
opts
.
baseConfig
(),
conn
:
c
,
baseCtx
:
baseCtx
,
remoteAddrStr
:
c
.
RemoteAddr
()
.
String
(),
bw
:
newBufferedWriter
(
c
),
handler
:
opts
.
handler
(),
...
...
@@ -273,13 +276,14 @@ func (s *Server) ServeConn(c net.Conn, opts *ServeConnOpts) {
serveG
:
newGoroutineLock
(),
pushEnabled
:
true
,
}
sc
.
flow
.
add
(
initialWindowSize
)
sc
.
inflow
.
add
(
initialWindowSize
)
sc
.
hpackEncoder
=
hpack
.
NewEncoder
(
&
sc
.
headerWriteBuf
)
sc
.
hpackDecoder
=
hpack
.
NewDecoder
(
initialHeaderTableSize
,
nil
)
sc
.
hpackDecoder
.
SetMaxStringLength
(
sc
.
maxHeaderStringLen
())
fr
:=
NewFramer
(
sc
.
bw
,
c
)
fr
.
ReadMetaHeaders
=
hpack
.
NewDecoder
(
initialHeaderTableSize
,
nil
)
fr
.
MaxHeaderListSize
=
sc
.
maxHeaderListSize
()
fr
.
SetMaxReadFrameSize
(
s
.
maxReadFrameSize
())
sc
.
framer
=
fr
...
...
@@ -335,30 +339,6 @@ func (s *Server) ServeConn(c net.Conn, opts *ServeConnOpts) {
sc
.
serve
()
}
// isBadCipher reports whether the cipher is blacklisted by the HTTP/2 spec.
func
isBadCipher
(
cipher
uint16
)
bool
{
switch
cipher
{
case
tls
.
TLS_RSA_WITH_RC4_128_SHA
,
tls
.
TLS_RSA_WITH_3DES_EDE_CBC_SHA
,
tls
.
TLS_RSA_WITH_AES_128_CBC_SHA
,
tls
.
TLS_RSA_WITH_AES_256_CBC_SHA
,
tls
.
TLS_ECDHE_ECDSA_WITH_RC4_128_SHA
,
tls
.
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
,
tls
.
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
,
tls
.
TLS_ECDHE_RSA_WITH_RC4_128_SHA
,
tls
.
TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA
,
tls
.
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
,
tls
.
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
:
// Reject cipher suites from Appendix A.
// "This list includes those cipher suites that do not
// offer an ephemeral key exchange and those that are
// based on the TLS null, stream or block cipher type"
return
true
default
:
return
false
}
}
func
(
sc
*
serverConn
)
rejectConn
(
err
ErrCode
,
debug
string
)
{
sc
.
vlogf
(
"http2: server rejecting conn: %v, %s"
,
err
,
debug
)
// ignoring errors. hanging up anyway.
...
...
@@ -374,8 +354,8 @@ type serverConn struct {
conn
net
.
Conn
bw
*
bufferedWriter
// writing to conn
handler
http
.
Handler
baseCtx
contextContext
framer
*
Framer
hpackDecoder
*
hpack
.
Decoder
doneServing
chan
struct
{}
// closed when serverConn.serve ends
readFrameCh
chan
readFrameResult
// written by serverConn.readFrames
wantWriteFrameCh
chan
frameWriteMsg
// from handlers -> serve
...
...
@@ -402,7 +382,6 @@ type serverConn struct {
headerTableSize
uint32
peerMaxHeaderListSize
uint32
// zero means unknown (default)
canonHeader
map
[
string
]
string
// http2-lower-case -> Go-Canonical-Case
req
requestParam
// non-zero while reading request headers
writingFrame
bool
// started write goroutine but haven't heard back on wroteFrameCh
needsFrameFlush
bool
// last frame write wasn't a flush
writeSched
writeScheduler
...
...
@@ -411,22 +390,13 @@ type serverConn struct {
goAwayCode
ErrCode
shutdownTimerCh
<-
chan
time
.
Time
// nil until used
shutdownTimer
*
time
.
Timer
// nil until used
freeRequestBodyBuf
[]
byte
// if non-nil, a free initialWindowSize buffer for getRequestBodyBuf
// Owned by the writeFrameAsync goroutine:
headerWriteBuf
bytes
.
Buffer
hpackEncoder
*
hpack
.
Encoder
}
func
(
sc
*
serverConn
)
maxHeaderStringLen
()
int
{
v
:=
sc
.
maxHeaderListSize
()
if
uint32
(
int
(
v
))
==
v
{
return
int
(
v
)
}
// They had a crazy big number for MaxHeaderBytes anyway,
// so give them unlimited header lengths:
return
0
}
func
(
sc
*
serverConn
)
maxHeaderListSize
()
uint32
{
n
:=
sc
.
hs
.
MaxHeaderBytes
if
n
<=
0
{
...
...
@@ -439,21 +409,6 @@ func (sc *serverConn) maxHeaderListSize() uint32 {
return
uint32
(
n
+
typicalHeaders
*
perFieldOverhead
)
}
// requestParam is the state of the next request, initialized over
// potentially several frames HEADERS + zero or more CONTINUATION
// frames.
type
requestParam
struct
{
// stream is non-nil if we're reading (HEADER or CONTINUATION)
// frames for a request (but not DATA).
stream
*
stream
header
http
.
Header
method
,
path
string
scheme
,
authority
string
sawRegularHeader
bool
// saw a non-pseudo header already
invalidHeader
bool
// an invalid header was seen
headerListSize
int64
// actually uint32, but easier math this way
}
// stream represents a stream. This is the minimal metadata needed by
// the serve goroutine. Most of the actual stream state is owned by
// the http.Handler's goroutine in the responseWriter. Because the
...
...
@@ -463,10 +418,12 @@ type requestParam struct {
// responseWriter's state field.
type
stream
struct
{
// immutable:
sc
*
serverConn
id
uint32
body
*
pipe
// non-nil if expecting DATA frames
cw
closeWaiter
// closed wait stream transitions to closed state
sc
*
serverConn
id
uint32
body
*
pipe
// non-nil if expecting DATA frames
cw
closeWaiter
// closed wait stream transitions to closed state
ctx
contextContext
cancelCtx
func
()
// owned by serverConn's serve loop:
bodyBytes
int64
// body bytes seen so far
...
...
@@ -480,6 +437,8 @@ type stream struct {
sentReset
bool
// only true once detached from streams map
gotReset
bool
// only true once detacted from streams map
gotTrailerHeader
bool
// HEADER frame for trailers was seen
wroteHeaders
bool
// whether we wrote headers (not status 100)
reqBuf
[]
byte
trailer
http
.
Header
// accumulated trailers
reqTrailer
http
.
Header
// handler's Request.Trailer
...
...
@@ -589,87 +548,6 @@ func (sc *serverConn) condlogf(err error, format string, args ...interface{}) {
}
}
func
(
sc
*
serverConn
)
onNewHeaderField
(
f
hpack
.
HeaderField
)
{
sc
.
serveG
.
check
()
if
VerboseLogs
{
sc
.
vlogf
(
"http2: server decoded %v"
,
f
)
}
switch
{
case
!
validHeaderFieldValue
(
f
.
Value
)
:
// f.Name checked _after_ pseudo check, since ':' is invalid
sc
.
req
.
invalidHeader
=
true
case
strings
.
HasPrefix
(
f
.
Name
,
":"
)
:
if
sc
.
req
.
sawRegularHeader
{
sc
.
logf
(
"pseudo-header after regular header"
)
sc
.
req
.
invalidHeader
=
true
return
}
var
dst
*
string
switch
f
.
Name
{
case
":method"
:
dst
=
&
sc
.
req
.
method
case
":path"
:
dst
=
&
sc
.
req
.
path
case
":scheme"
:
dst
=
&
sc
.
req
.
scheme
case
":authority"
:
dst
=
&
sc
.
req
.
authority
default
:
// 8.1.2.1 Pseudo-Header Fields
// "Endpoints MUST treat a request or response
// that contains undefined or invalid
// pseudo-header fields as malformed (Section
// 8.1.2.6)."
sc
.
logf
(
"invalid pseudo-header %q"
,
f
.
Name
)
sc
.
req
.
invalidHeader
=
true
return
}
if
*
dst
!=
""
{
sc
.
logf
(
"duplicate pseudo-header %q sent"
,
f
.
Name
)
sc
.
req
.
invalidHeader
=
true
return
}
*
dst
=
f
.
Value
case
!
validHeaderFieldName
(
f
.
Name
)
:
sc
.
req
.
invalidHeader
=
true
default
:
sc
.
req
.
sawRegularHeader
=
true
sc
.
req
.
header
.
Add
(
sc
.
canonicalHeader
(
f
.
Name
),
f
.
Value
)
const
headerFieldOverhead
=
32
// per spec
sc
.
req
.
headerListSize
+=
int64
(
len
(
f
.
Name
))
+
int64
(
len
(
f
.
Value
))
+
headerFieldOverhead
if
sc
.
req
.
headerListSize
>
int64
(
sc
.
maxHeaderListSize
())
{
sc
.
hpackDecoder
.
SetEmitEnabled
(
false
)
}
}
}
func
(
st
*
stream
)
onNewTrailerField
(
f
hpack
.
HeaderField
)
{
sc
:=
st
.
sc
sc
.
serveG
.
check
()
if
VerboseLogs
{
sc
.
vlogf
(
"http2: server decoded trailer %v"
,
f
)
}
switch
{
case
strings
.
HasPrefix
(
f
.
Name
,
":"
)
:
sc
.
req
.
invalidHeader
=
true
return
case
!
validHeaderFieldName
(
f
.
Name
)
||
!
validHeaderFieldValue
(
f
.
Value
)
:
sc
.
req
.
invalidHeader
=
true
return
default
:
key
:=
sc
.
canonicalHeader
(
f
.
Name
)
if
st
.
trailer
!=
nil
{
vv
:=
append
(
st
.
trailer
[
key
],
f
.
Value
)
st
.
trailer
[
key
]
=
vv
// arbitrary; TODO: read spec about header list size limits wrt trailers
const
tooBig
=
1000
if
len
(
vv
)
>=
tooBig
{
sc
.
hpackDecoder
.
SetEmitEnabled
(
false
)
}
}
}
}
func
(
sc
*
serverConn
)
canonicalHeader
(
v
string
)
string
{
sc
.
serveG
.
check
()
cv
,
ok
:=
commonCanonHeader
[
v
]
...
...
@@ -704,10 +582,11 @@ type readFrameResult struct {
// It's run on its own goroutine.
func
(
sc
*
serverConn
)
readFrames
()
{
gate
:=
make
(
gate
)
gateDone
:=
gate
.
Done
for
{
f
,
err
:=
sc
.
framer
.
ReadFrame
()
select
{
case
sc
.
readFrameCh
<-
readFrameResult
{
f
,
err
,
gate
.
Done
}
:
case
sc
.
readFrameCh
<-
readFrameResult
{
f
,
err
,
gateDone
}
:
case
<-
sc
.
doneServing
:
return
}
...
...
@@ -946,7 +825,23 @@ func (sc *serverConn) writeFrameFromHandler(wm frameWriteMsg) error {
// If you're not on the serve goroutine, use writeFrameFromHandler instead.
func
(
sc
*
serverConn
)
writeFrame
(
wm
frameWriteMsg
)
{
sc
.
serveG
.
check
()
sc
.
writeSched
.
add
(
wm
)
var
ignoreWrite
bool
// Don't send a 100-continue response if we've already sent headers.
// See golang.org/issue/14030.
switch
wm
.
write
.
(
type
)
{
case
*
writeResHeaders
:
wm
.
stream
.
wroteHeaders
=
true
case
write100ContinueHeadersFrame
:
if
wm
.
stream
.
wroteHeaders
{
ignoreWrite
=
true
}
}
if
!
ignoreWrite
{
sc
.
writeSched
.
add
(
wm
)
}
sc
.
scheduleFrameWrite
()
}
...
...
@@ -1183,10 +1078,8 @@ func (sc *serverConn) processFrame(f Frame) error {
switch
f
:=
f
.
(
type
)
{
case
*
SettingsFrame
:
return
sc
.
processSettings
(
f
)
case
*
HeadersFrame
:
case
*
Meta
HeadersFrame
:
return
sc
.
processHeaders
(
f
)
case
*
ContinuationFrame
:
return
sc
.
processContinuation
(
f
)
case
*
WindowUpdateFrame
:
return
sc
.
processWindowUpdate
(
f
)
case
*
PingFrame
:
...
...
@@ -1265,6 +1158,7 @@ func (sc *serverConn) processResetStream(f *RSTStreamFrame) error {
}
if
st
!=
nil
{
st
.
gotReset
=
true
st
.
cancelCtx
()
sc
.
closeStream
(
st
,
StreamError
{
f
.
StreamID
,
f
.
ErrCode
})
}
return
nil
...
...
@@ -1286,6 +1180,18 @@ func (sc *serverConn) closeStream(st *stream, err error) {
}
st
.
cw
.
Close
()
// signals Handler's CloseNotifier, unblocks writes, etc
sc
.
writeSched
.
forgetStream
(
st
.
id
)
if
st
.
reqBuf
!=
nil
{
// Stash this request body buffer (64k) away for reuse
// by a future POST/PUT/etc.
//
// TODO(bradfitz): share on the server? sync.Pool?
// Server requires locks and might hurt contention.
// sync.Pool might work, or might be worse, depending
// on goroutine CPU migrations. (get and put on
// separate CPUs). Maybe a mix of strategies. But
// this is an easy win for now.
sc
.
freeRequestBodyBuf
=
st
.
reqBuf
}
}
func
(
sc
*
serverConn
)
processSettings
(
f
*
SettingsFrame
)
error
{
...
...
@@ -1442,7 +1348,7 @@ func (st *stream) copyTrailersToHandlerRequest() {
}
}
func
(
sc
*
serverConn
)
processHeaders
(
f
*
HeadersFrame
)
error
{
func
(
sc
*
serverConn
)
processHeaders
(
f
*
Meta
HeadersFrame
)
error
{
sc
.
serveG
.
check
()
id
:=
f
.
Header
()
.
StreamID
if
sc
.
inGoAway
{
...
...
@@ -1471,17 +1377,18 @@ func (sc *serverConn) processHeaders(f *HeadersFrame) error {
// endpoint has opened or reserved. [...] An endpoint that
// receives an unexpected stream identifier MUST respond with
// a connection error (Section 5.4.1) of type PROTOCOL_ERROR.
if
id
<=
sc
.
maxStreamID
||
sc
.
req
.
stream
!=
nil
{
if
id
<=
sc
.
maxStreamID
{
return
ConnectionError
(
ErrCodeProtocol
)
}
sc
.
maxStreamID
=
id
if
id
>
sc
.
maxStreamID
{
sc
.
maxStreamID
=
id
}
ctx
,
cancelCtx
:=
contextWithCancel
(
sc
.
baseCtx
)
st
=
&
stream
{
sc
:
sc
,
id
:
id
,
state
:
stateOpen
,
sc
:
sc
,
id
:
id
,
state
:
stateOpen
,
ctx
:
ctx
,
cancelCtx
:
cancelCtx
,
}
if
f
.
StreamEnded
()
{
st
.
state
=
stateHalfClosedRemote
...
...
@@ -1501,50 +1408,6 @@ func (sc *serverConn) processHeaders(f *HeadersFrame) error {
if
sc
.
curOpenStreams
==
1
{
sc
.
setConnState
(
http
.
StateActive
)
}
sc
.
req
=
requestParam
{
stream
:
st
,
header
:
make
(
http
.
Header
),
}
sc
.
hpackDecoder
.
SetEmitFunc
(
sc
.
onNewHeaderField
)
sc
.
hpackDecoder
.
SetEmitEnabled
(
true
)
return
sc
.
processHeaderBlockFragment
(
st
,
f
.
HeaderBlockFragment
(),
f
.
HeadersEnded
())
}
func
(
st
*
stream
)
processTrailerHeaders
(
f
*
HeadersFrame
)
error
{
sc
:=
st
.
sc
sc
.
serveG
.
check
()
if
st
.
gotTrailerHeader
{
return
ConnectionError
(
ErrCodeProtocol
)
}
st
.
gotTrailerHeader
=
true
if
!
f
.
StreamEnded
()
{
return
StreamError
{
st
.
id
,
ErrCodeProtocol
}
}
sc
.
resetPendingRequest
()
// we use invalidHeader from it for trailers
return
st
.
processTrailerHeaderBlockFragment
(
f
.
HeaderBlockFragment
(),
f
.
HeadersEnded
())
}
func
(
sc
*
serverConn
)
processContinuation
(
f
*
ContinuationFrame
)
error
{
sc
.
serveG
.
check
()
st
:=
sc
.
streams
[
f
.
Header
()
.
StreamID
]
if
st
.
gotTrailerHeader
{
return
st
.
processTrailerHeaderBlockFragment
(
f
.
HeaderBlockFragment
(),
f
.
HeadersEnded
())
}
return
sc
.
processHeaderBlockFragment
(
st
,
f
.
HeaderBlockFragment
(),
f
.
HeadersEnded
())
}
func
(
sc
*
serverConn
)
processHeaderBlockFragment
(
st
*
stream
,
frag
[]
byte
,
end
bool
)
error
{
sc
.
serveG
.
check
()
if
_
,
err
:=
sc
.
hpackDecoder
.
Write
(
frag
);
err
!=
nil
{
return
ConnectionError
(
ErrCodeCompression
)
}
if
!
end
{
return
nil
}
if
err
:=
sc
.
hpackDecoder
.
Close
();
err
!=
nil
{
return
ConnectionError
(
ErrCodeCompression
)
}
defer
sc
.
resetPendingRequest
()
if
sc
.
curOpenStreams
>
sc
.
advMaxStreams
{
// "Endpoints MUST NOT exceed the limit set by their
// peer. An endpoint that receives a HEADERS frame
...
...
@@ -1564,7 +1427,7 @@ func (sc *serverConn) processHeaderBlockFragment(st *stream, frag []byte, end bo
return
StreamError
{
st
.
id
,
ErrCodeRefusedStream
}
}
rw
,
req
,
err
:=
sc
.
newWriterAndRequest
()
rw
,
req
,
err
:=
sc
.
newWriterAndRequest
(
st
,
f
)
if
err
!=
nil
{
return
err
}
...
...
@@ -1576,36 +1439,44 @@ func (sc *serverConn) processHeaderBlockFragment(st *stream, frag []byte, end bo
st
.
declBodyBytes
=
req
.
ContentLength
handler
:=
sc
.
handler
.
ServeHTTP
if
!
sc
.
hpackDecoder
.
EmitEnabled
()
{
if
f
.
Truncated
{
// Their header list was too long. Send a 431 error.
handler
=
handleHeaderListTooLong
}
else
if
err
:=
checkValidHTTP2Request
(
req
);
err
!=
nil
{
handler
=
new400Handler
(
err
)
}
go
sc
.
runHandler
(
rw
,
req
,
handler
)
return
nil
}
func
(
st
*
stream
)
processTrailerHeader
BlockFragment
(
frag
[]
byte
,
end
bool
)
error
{
func
(
st
*
stream
)
processTrailerHeader
s
(
f
*
MetaHeadersFrame
)
error
{
sc
:=
st
.
sc
sc
.
serveG
.
check
()
sc
.
hpackDecoder
.
SetEmitFunc
(
st
.
onNewTrailerField
)
if
_
,
err
:=
sc
.
hpackDecoder
.
Write
(
frag
);
err
!=
nil
{
return
ConnectionError
(
ErrCodeCompression
)
if
st
.
gotTrailerHeader
{
return
ConnectionError
(
ErrCodeProtocol
)
}
if
!
end
{
return
nil
st
.
gotTrailerHeader
=
true
if
!
f
.
StreamEnded
()
{
return
StreamError
{
st
.
id
,
ErrCodeProtocol
}
}
rp
:=
&
sc
.
req
if
rp
.
invalidHeader
{
return
StreamError
{
rp
.
stream
.
id
,
ErrCodeProtocol
}
if
len
(
f
.
PseudoFields
())
>
0
{
return
StreamError
{
st
.
id
,
ErrCodeProtocol
}
}
err
:=
sc
.
hpackDecoder
.
Close
()
st
.
endStream
()
if
err
!=
nil
{
return
ConnectionError
(
ErrCodeCompression
)
if
st
.
trailer
!=
nil
{
for
_
,
hf
:=
range
f
.
RegularFields
()
{
key
:=
sc
.
canonicalHeader
(
hf
.
Name
)
if
!
ValidTrailerHeader
(
key
)
{
// TODO: send more details to the peer somehow. But http2 has
// no way to send debug data at a stream level. Discuss with
// HTTP folk.
return
StreamError
{
st
.
id
,
ErrCodeProtocol
}
}
st
.
trailer
[
key
]
=
append
(
st
.
trailer
[
key
],
hf
.
Value
)
}
}
st
.
endStream
()
return
nil
}
...
...
@@ -1650,29 +1521,21 @@ func adjustStreamPriority(streams map[uint32]*stream, streamID uint32, priority
}
}
// resetPendingRequest zeros out all state related to a HEADERS frame
// and its zero or more CONTINUATION frames sent to start a new
// request.
func
(
sc
*
serverConn
)
resetPendingRequest
()
{
sc
.
serveG
.
check
()
sc
.
req
=
requestParam
{}
}
func
(
sc
*
serverConn
)
newWriterAndRequest
()
(
*
responseWriter
,
*
http
.
Request
,
error
)
{
func
(
sc
*
serverConn
)
newWriterAndRequest
(
st
*
stream
,
f
*
MetaHeadersFrame
)
(
*
responseWriter
,
*
http
.
Request
,
error
)
{
sc
.
serveG
.
check
()
rp
:=
&
sc
.
req
if
rp
.
invalidHeader
{
return
nil
,
nil
,
StreamError
{
rp
.
stream
.
id
,
ErrCodeProtocol
}
}
method
:=
f
.
PseudoValue
(
"method"
)
path
:=
f
.
PseudoValue
(
"path"
)
scheme
:=
f
.
PseudoValue
(
"scheme"
)
authority
:=
f
.
PseudoValue
(
"authority"
)
isConnect
:=
rp
.
method
==
"CONNECT"
isConnect
:=
method
==
"CONNECT"
if
isConnect
{
if
rp
.
path
!=
""
||
rp
.
scheme
!=
""
||
rp
.
authority
==
""
{
return
nil
,
nil
,
StreamError
{
rp
.
stream
.
id
,
ErrCodeProtocol
}
if
path
!=
""
||
scheme
!=
""
||
authority
==
""
{
return
nil
,
nil
,
StreamError
{
f
.
StreamID
,
ErrCodeProtocol
}
}
}
else
if
rp
.
method
==
""
||
rp
.
path
==
""
||
(
rp
.
scheme
!=
"https"
&&
rp
.
scheme
!=
"http"
)
{
}
else
if
method
==
""
||
path
==
""
||
(
scheme
!=
"https"
&&
scheme
!=
"http"
)
{
// See 8.1.2.6 Malformed Requests and Responses:
//
// Malformed requests or responses that are detected
...
...
@@ -1683,35 +1546,40 @@ func (sc *serverConn) newWriterAndRequest() (*responseWriter, *http.Request, err
// "All HTTP/2 requests MUST include exactly one valid
// value for the :method, :scheme, and :path
// pseudo-header fields"
return
nil
,
nil
,
StreamError
{
rp
.
stream
.
id
,
ErrCodeProtocol
}
return
nil
,
nil
,
StreamError
{
f
.
StreamID
,
ErrCodeProtocol
}
}
bodyOpen
:=
rp
.
stream
.
state
==
stateOpen
if
rp
.
method
==
"HEAD"
&&
bodyOpen
{
bodyOpen
:=
!
f
.
StreamEnded
()
if
method
==
"HEAD"
&&
bodyOpen
{
// HEAD requests can't have bodies
return
nil
,
nil
,
StreamError
{
rp
.
stream
.
id
,
ErrCodeProtocol
}
return
nil
,
nil
,
StreamError
{
f
.
StreamID
,
ErrCodeProtocol
}
}
var
tlsState
*
tls
.
ConnectionState
// nil if not scheme https
if
rp
.
scheme
==
"https"
{
if
scheme
==
"https"
{
tlsState
=
sc
.
tlsState
}
authority
:=
rp
.
authority
header
:=
make
(
http
.
Header
)
for
_
,
hf
:=
range
f
.
RegularFields
()
{
header
.
Add
(
sc
.
canonicalHeader
(
hf
.
Name
),
hf
.
Value
)
}
if
authority
==
""
{
authority
=
rp
.
header
.
Get
(
"Host"
)
authority
=
header
.
Get
(
"Host"
)
}
needsContinue
:=
rp
.
header
.
Get
(
"Expect"
)
==
"100-continue"
needsContinue
:=
header
.
Get
(
"Expect"
)
==
"100-continue"
if
needsContinue
{
rp
.
header
.
Del
(
"Expect"
)
header
.
Del
(
"Expect"
)
}
// Merge Cookie headers into one "; "-delimited value.
if
cookies
:=
rp
.
header
[
"Cookie"
];
len
(
cookies
)
>
1
{
rp
.
header
.
Set
(
"Cookie"
,
strings
.
Join
(
cookies
,
"; "
))
if
cookies
:=
header
[
"Cookie"
];
len
(
cookies
)
>
1
{
header
.
Set
(
"Cookie"
,
strings
.
Join
(
cookies
,
"; "
))
}
// Setup Trailers
var
trailer
http
.
Header
for
_
,
v
:=
range
rp
.
header
[
"Trailer"
]
{
for
_
,
v
:=
range
header
[
"Trailer"
]
{
for
_
,
key
:=
range
strings
.
Split
(
v
,
","
)
{
key
=
http
.
CanonicalHeaderKey
(
strings
.
TrimSpace
(
key
))
switch
key
{
...
...
@@ -1726,31 +1594,31 @@ func (sc *serverConn) newWriterAndRequest() (*responseWriter, *http.Request, err
}
}
}
delete
(
rp
.
header
,
"Trailer"
)
delete
(
header
,
"Trailer"
)
body
:=
&
requestBody
{
conn
:
sc
,
stream
:
rp
.
stream
,
stream
:
st
,
needsContinue
:
needsContinue
,
}
var
url_
*
url
.
URL
var
requestURI
string
if
isConnect
{
url_
=
&
url
.
URL
{
Host
:
rp
.
authority
}
requestURI
=
rp
.
authority
// mimic HTTP/1 server behavior
url_
=
&
url
.
URL
{
Host
:
authority
}
requestURI
=
authority
// mimic HTTP/1 server behavior
}
else
{
var
err
error
url_
,
err
=
url
.
ParseRequestURI
(
rp
.
path
)
url_
,
err
=
url
.
ParseRequestURI
(
path
)
if
err
!=
nil
{
return
nil
,
nil
,
StreamError
{
rp
.
stream
.
id
,
ErrCodeProtocol
}
return
nil
,
nil
,
StreamError
{
f
.
StreamID
,
ErrCodeProtocol
}
}
requestURI
=
rp
.
path
requestURI
=
path
}
req
:=
&
http
.
Request
{
Method
:
rp
.
method
,
Method
:
method
,
URL
:
url_
,
RemoteAddr
:
sc
.
remoteAddrStr
,
Header
:
rp
.
header
,
Header
:
header
,
RequestURI
:
requestURI
,
Proto
:
"HTTP/2.0"
,
ProtoMajor
:
2
,
...
...
@@ -1760,12 +1628,18 @@ func (sc *serverConn) newWriterAndRequest() (*responseWriter, *http.Request, err
Body
:
body
,
Trailer
:
trailer
,
}
req
=
requestWithContext
(
req
,
st
.
ctx
)
if
bodyOpen
{
// Disabled, per golang.org/issue/14960:
// st.reqBuf = sc.getRequestBodyBuf()
// TODO: remove this 64k of garbage per request (again, but without a data race):
buf
:=
make
([]
byte
,
initialWindowSize
)
body
.
pipe
=
&
pipe
{
b
:
&
fixedBuffer
{
buf
:
make
([]
byte
,
initialWindowSize
)},
// TODO: garbage
b
:
&
fixedBuffer
{
buf
:
buf
},
}
if
vv
,
ok
:=
rp
.
header
[
"Content-Length"
];
ok
{
if
vv
,
ok
:=
header
[
"Content-Length"
];
ok
{
req
.
ContentLength
,
_
=
strconv
.
ParseInt
(
vv
[
0
],
10
,
64
)
}
else
{
req
.
ContentLength
=
-
1
...
...
@@ -1778,7 +1652,7 @@ func (sc *serverConn) newWriterAndRequest() (*responseWriter, *http.Request, err
rws
.
conn
=
sc
rws
.
bw
=
bwSave
rws
.
bw
.
Reset
(
chunkWriter
{
rws
})
rws
.
stream
=
rp
.
stream
rws
.
stream
=
st
rws
.
req
=
req
rws
.
body
=
body
...
...
@@ -1786,10 +1660,20 @@ func (sc *serverConn) newWriterAndRequest() (*responseWriter, *http.Request, err
return
rw
,
req
,
nil
}
func
(
sc
*
serverConn
)
getRequestBodyBuf
()
[]
byte
{
sc
.
serveG
.
check
()
if
buf
:=
sc
.
freeRequestBodyBuf
;
buf
!=
nil
{
sc
.
freeRequestBodyBuf
=
nil
return
buf
}
return
make
([]
byte
,
initialWindowSize
)
}
// Run on its own goroutine.
func
(
sc
*
serverConn
)
runHandler
(
rw
*
responseWriter
,
req
*
http
.
Request
,
handler
func
(
http
.
ResponseWriter
,
*
http
.
Request
))
{
didPanic
:=
true
defer
func
()
{
rw
.
rws
.
stream
.
cancelCtx
()
if
didPanic
{
e
:=
recover
()
// Same as net/http:
...
...
@@ -1942,7 +1826,7 @@ type requestBody struct {
func
(
b
*
requestBody
)
Close
()
error
{
if
b
.
pipe
!=
nil
{
b
.
pipe
.
Close
WithError
(
errClosedBody
)
b
.
pipe
.
Break
WithError
(
errClosedBody
)
}
b
.
closed
=
true
return
nil
...
...
@@ -2017,9 +1901,9 @@ func (rws *responseWriterState) hasTrailers() bool { return len(rws.trailers) !=
// written in the trailers at the end of the response.
func
(
rws
*
responseWriterState
)
declareTrailer
(
k
string
)
{
k
=
http
.
CanonicalHeaderKey
(
k
)
switch
k
{
case
"Transfer-Encoding"
,
"Content-Length"
,
"Trailer"
:
if
!
ValidTrailerHeader
(
k
)
{
// Forbidden by RFC 2616 14.40.
rws
.
conn
.
logf
(
"ignoring invalid trailer %q"
,
k
)
return
}
if
!
strSliceContains
(
rws
.
trailers
,
k
)
{
...
...
@@ -2160,7 +2044,12 @@ func (rws *responseWriterState) promoteUndeclaredTrailers() {
rws
.
declareTrailer
(
trailerKey
)
rws
.
handlerHeader
[
http
.
CanonicalHeaderKey
(
trailerKey
)]
=
vv
}
sort
.
Strings
(
rws
.
trailers
)
if
len
(
rws
.
trailers
)
>
1
{
sorter
:=
sorterPool
.
Get
()
.
(
*
sorter
)
sorter
.
SortStrings
(
rws
.
trailers
)
sorterPool
.
Put
(
sorter
)
}
}
func
(
w
*
responseWriter
)
Flush
()
{
...
...
@@ -2306,3 +2195,69 @@ func foreachHeaderElement(v string, fn func(string)) {
}
}
}
// From http://httpwg.org/specs/rfc7540.html#rfc.section.8.1.2.2
var
connHeaders
=
[]
string
{
"Connection"
,
"Keep-Alive"
,
"Proxy-Connection"
,
"Transfer-Encoding"
,
"Upgrade"
,
}
// checkValidHTTP2Request checks whether req is a valid HTTP/2 request,
// per RFC 7540 Section 8.1.2.2.
// The returned error is reported to users.
func
checkValidHTTP2Request
(
req
*
http
.
Request
)
error
{
for
_
,
h
:=
range
connHeaders
{
if
_
,
ok
:=
req
.
Header
[
h
];
ok
{
return
fmt
.
Errorf
(
"request header %q is not valid in HTTP/2"
,
h
)
}
}
te
:=
req
.
Header
[
"Te"
]
if
len
(
te
)
>
0
&&
(
len
(
te
)
>
1
||
(
te
[
0
]
!=
"trailers"
&&
te
[
0
]
!=
""
))
{
return
errors
.
New
(
`request header "TE" may only be "trailers" in HTTP/2`
)
}
return
nil
}
func
new400Handler
(
err
error
)
http
.
HandlerFunc
{
return
func
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
http
.
Error
(
w
,
err
.
Error
(),
http
.
StatusBadRequest
)
}
}
// ValidTrailerHeader reports whether name is a valid header field name to appear
// in trailers.
// See: http://tools.ietf.org/html/rfc7230#section-4.1.2
func
ValidTrailerHeader
(
name
string
)
bool
{
name
=
http
.
CanonicalHeaderKey
(
name
)
if
strings
.
HasPrefix
(
name
,
"If-"
)
||
badTrailer
[
name
]
{
return
false
}
return
true
}
var
badTrailer
=
map
[
string
]
bool
{
"Authorization"
:
true
,
"Cache-Control"
:
true
,
"Connection"
:
true
,
"Content-Encoding"
:
true
,
"Content-Length"
:
true
,
"Content-Range"
:
true
,
"Content-Type"
:
true
,
"Expect"
:
true
,
"Host"
:
true
,
"Keep-Alive"
:
true
,
"Max-Forwards"
:
true
,
"Pragma"
:
true
,
"Proxy-Authenticate"
:
true
,
"Proxy-Authorization"
:
true
,
"Proxy-Connection"
:
true
,
"Range"
:
true
,
"Realm"
:
true
,
"Te"
:
true
,
"Trailer"
:
true
,
"Transfer-Encoding"
:
true
,
"Www-Authenticate"
:
true
,
}
vendor/golang.org/x/net/http2/transport.go
View file @
e5ed62e8
...
...
@@ -25,6 +25,7 @@ import (
"time"
"golang.org/x/net/http2/hpack"
"golang.org/x/net/lex/httplex"
)
const
(
...
...
@@ -76,6 +77,10 @@ type Transport struct {
// uncompressed.
DisableCompression
bool
// AllowHTTP, if true, permits HTTP/2 requests using the insecure,
// plain-text "http" scheme. Note that this does not enable h2c support.
AllowHTTP
bool
// MaxHeaderListSize is the http2 SETTINGS_MAX_HEADER_LIST_SIZE to
// send in the initial settings frame. It is how many bytes
// of response headers are allow. Unlike the http2 spec, zero here
...
...
@@ -134,9 +139,10 @@ func (t *Transport) initConnPool() {
// ClientConn is the state of a single HTTP/2 client connection to an
// HTTP/2 server.
type
ClientConn
struct
{
t
*
Transport
tconn
net
.
Conn
// usually *tls.Conn, except specialized impls
tlsState
*
tls
.
ConnectionState
// nil only for specialized impls
t
*
Transport
tconn
net
.
Conn
// usually *tls.Conn, except specialized impls
tlsState
*
tls
.
ConnectionState
// nil only for specialized impls
singleUse
bool
// whether being used for a single http.Request
// readLoop goroutine fields:
readerDone
chan
struct
{}
// closed on error
...
...
@@ -148,11 +154,14 @@ type ClientConn struct {
inflow
flow
// peer's conn-level flow control
closed
bool
goAway
*
GoAwayFrame
// if non-nil, the GoAwayFrame we received
goAwayDebug
string
// goAway frame's debug data, retained as a string
streams
map
[
uint32
]
*
clientStream
// client-initiated
nextStreamID
uint32
bw
*
bufio
.
Writer
br
*
bufio
.
Reader
fr
*
Framer
lastActive
time
.
Time
// Settings from peer:
maxFrameSize
uint32
maxConcurrentStreams
uint32
...
...
@@ -170,10 +179,12 @@ type ClientConn struct {
type
clientStream
struct
{
cc
*
ClientConn
req
*
http
.
Request
trace
*
clientTrace
// or nil
ID
uint32
resc
chan
resAndError
bufPipe
pipe
// buffered pipe with the flow-controlled response payload
requestedGzip
bool
on100
func
()
// optional code to run if get a 100 continue response
flow
flow
// guarded by cc.mu
inflow
flow
// guarded by cc.mu
...
...
@@ -187,36 +198,43 @@ type clientStream struct {
done
chan
struct
{}
// closed when stream remove from cc.streams map; close calls guarded by cc.mu
// owned by clientConnReadLoop:
pastHeaders
bool
// got HEADERS w/ END_HEADERS
pastTrailers
bool
// got second HEADERS frame w/ END_HEADERS
firstByte
bool
// got the first response byte
pastHeaders
bool
// got first MetaHeadersFrame (actual headers)
pastTrailers
bool
// got optional second MetaHeadersFrame (trailers)
trailer
http
.
Header
// accumulated trailers
resTrailer
*
http
.
Header
// client's Response.Trailer
}
// awaitRequestCancel runs in its own goroutine and waits for the user
// to either cancel a RoundTrip request (using the provided
// Request.Cancel channel), or for the request to be done (any way it
// might be removed from the cc.streams map: peer reset, successful
// completion, TCP connection breakage, etc)
func
(
cs
*
clientStream
)
awaitRequestCancel
(
cancel
<-
chan
struct
{})
{
if
cancel
==
nil
{
// to cancel a RoundTrip request, its context to expire, or for the
// request to be done (any way it might be removed from the cc.streams
// map: peer reset, successful completion, TCP connection breakage,
// etc)
func
(
cs
*
clientStream
)
awaitRequestCancel
(
req
*
http
.
Request
)
{
ctx
:=
reqContext
(
req
)
if
req
.
Cancel
==
nil
&&
ctx
.
Done
()
==
nil
{
return
}
select
{
case
<-
c
ancel
:
case
<-
req
.
C
ancel
:
cs
.
bufPipe
.
CloseWithError
(
errRequestCanceled
)
cs
.
cc
.
writeStreamReset
(
cs
.
ID
,
ErrCodeCancel
,
nil
)
case
<-
ctx
.
Done
()
:
cs
.
bufPipe
.
CloseWithError
(
ctx
.
Err
())
cs
.
cc
.
writeStreamReset
(
cs
.
ID
,
ErrCodeCancel
,
nil
)
case
<-
cs
.
done
:
}
}
// checkReset reports any error sent in a RST_STREAM frame by the
// server.
func
(
cs
*
clientStream
)
checkReset
()
error
{
// checkReset
OrDone
reports any error sent in a RST_STREAM frame by the
// server
, or errStreamClosed if the stream is complete
.
func
(
cs
*
clientStream
)
checkReset
OrDone
()
error
{
select
{
case
<-
cs
.
peerReset
:
return
cs
.
resetErr
case
<-
cs
.
done
:
return
errStreamClosed
default
:
return
nil
}
...
...
@@ -264,26 +282,31 @@ func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) {
// authorityAddr returns a given authority (a host/IP, or host:port / ip:port)
// and returns a host:port. The port 443 is added if needed.
func
authorityAddr
(
authority
string
)
(
addr
string
)
{
func
authorityAddr
(
scheme
string
,
authority
string
)
(
addr
string
)
{
if
_
,
_
,
err
:=
net
.
SplitHostPort
(
authority
);
err
==
nil
{
return
authority
}
return
net
.
JoinHostPort
(
authority
,
"443"
)
port
:=
"443"
if
scheme
==
"http"
{
port
=
"80"
}
return
net
.
JoinHostPort
(
authority
,
port
)
}
// RoundTripOpt is like RoundTrip, but takes options.
func
(
t
*
Transport
)
RoundTripOpt
(
req
*
http
.
Request
,
opt
RoundTripOpt
)
(
*
http
.
Response
,
error
)
{
if
req
.
URL
.
Scheme
!=
"https"
{
if
!
(
req
.
URL
.
Scheme
==
"https"
||
(
req
.
URL
.
Scheme
==
"http"
&&
t
.
AllowHTTP
))
{
return
nil
,
errors
.
New
(
"http2: unsupported scheme"
)
}
addr
:=
authorityAddr
(
req
.
URL
.
Host
)
addr
:=
authorityAddr
(
req
.
URL
.
Scheme
,
req
.
URL
.
Host
)
for
{
cc
,
err
:=
t
.
connPool
()
.
GetClientConn
(
req
,
addr
)
if
err
!=
nil
{
t
.
vlogf
(
"http2: Transport failed to get client conn for %s: %v"
,
addr
,
err
)
return
nil
,
err
}
traceGotConn
(
req
,
cc
)
res
,
err
:=
cc
.
RoundTrip
(
req
)
if
shouldRetryRequest
(
req
,
err
)
{
continue
...
...
@@ -300,7 +323,7 @@ func (t *Transport) RoundTripOpt(req *http.Request, opt RoundTripOpt) (*http.Res
// connected from previous requests but are now sitting idle.
// It does not interrupt any connections currently in use.
func
(
t
*
Transport
)
CloseIdleConnections
()
{
if
cp
,
ok
:=
t
.
connPool
()
.
(
*
clientConnPool
);
ok
{
if
cp
,
ok
:=
t
.
connPool
()
.
(
clientConnPoolIdleCloser
);
ok
{
cp
.
closeIdleConnections
()
}
}
...
...
@@ -333,8 +356,12 @@ func (t *Transport) newTLSConfig(host string) *tls.Config {
if
t
.
TLSClientConfig
!=
nil
{
*
cfg
=
*
t
.
TLSClientConfig
}
cfg
.
NextProtos
=
[]
string
{
NextProtoTLS
}
// TODO: don't override if already in list
cfg
.
ServerName
=
host
if
!
strSliceContains
(
cfg
.
NextProtos
,
NextProtoTLS
)
{
cfg
.
NextProtos
=
append
([]
string
{
NextProtoTLS
},
cfg
.
NextProtos
...
)
}
if
cfg
.
ServerName
==
""
{
cfg
.
ServerName
=
host
}
return
cfg
}
...
...
@@ -374,6 +401,13 @@ func (t *Transport) disableKeepAlives() bool {
return
t
.
t1
!=
nil
&&
t
.
t1
.
DisableKeepAlives
}
func
(
t
*
Transport
)
expectContinueTimeout
()
time
.
Duration
{
if
t
.
t1
==
nil
{
return
0
}
return
transportExpectContinueTimeout
(
t
.
t1
)
}
func
(
t
*
Transport
)
NewClientConn
(
c
net
.
Conn
)
(
*
ClientConn
,
error
)
{
if
VerboseLogs
{
t
.
vlogf
(
"http2: Transport creating client conn to %v"
,
c
.
RemoteAddr
())
...
...
@@ -401,6 +435,8 @@ func (t *Transport) NewClientConn(c net.Conn) (*ClientConn, error) {
cc
.
bw
=
bufio
.
NewWriter
(
stickyErrWriter
{
c
,
&
cc
.
werr
})
cc
.
br
=
bufio
.
NewReader
(
c
)
cc
.
fr
=
NewFramer
(
cc
.
bw
,
cc
.
br
)
cc
.
fr
.
ReadMetaHeaders
=
hpack
.
NewDecoder
(
initialHeaderTableSize
,
nil
)
cc
.
fr
.
MaxHeaderListSize
=
t
.
maxHeaderListSize
()
// TODO: SetMaxDynamicTableSize, SetMaxDynamicTableSizeLimit on
// henc in response to SETTINGS frames?
...
...
@@ -412,8 +448,8 @@ func (t *Transport) NewClientConn(c net.Conn) (*ClientConn, error) {
}
initialSettings
:=
[]
Setting
{
Setting
{
ID
:
SettingEnablePush
,
Val
:
0
},
Setting
{
ID
:
SettingInitialWindowSize
,
Val
:
transportDefaultStreamFlow
},
{
ID
:
SettingEnablePush
,
Val
:
0
},
{
ID
:
SettingInitialWindowSize
,
Val
:
transportDefaultStreamFlow
},
}
if
max
:=
t
.
maxHeaderListSize
();
max
!=
0
{
initialSettings
=
append
(
initialSettings
,
Setting
{
ID
:
SettingMaxHeaderListSize
,
Val
:
max
})
...
...
@@ -460,7 +496,17 @@ func (t *Transport) NewClientConn(c net.Conn) (*ClientConn, error) {
func
(
cc
*
ClientConn
)
setGoAway
(
f
*
GoAwayFrame
)
{
cc
.
mu
.
Lock
()
defer
cc
.
mu
.
Unlock
()
old
:=
cc
.
goAway
cc
.
goAway
=
f
// Merge the previous and current GoAway error frames.
if
cc
.
goAwayDebug
==
""
{
cc
.
goAwayDebug
=
string
(
f
.
DebugData
())
}
if
old
!=
nil
&&
old
.
ErrCode
!=
ErrCodeNo
{
cc
.
goAway
.
ErrCode
=
old
.
ErrCode
}
}
func
(
cc
*
ClientConn
)
CanTakeNewRequest
()
bool
{
...
...
@@ -470,6 +516,9 @@ func (cc *ClientConn) CanTakeNewRequest() bool {
}
func
(
cc
*
ClientConn
)
canTakeNewRequestLocked
()
bool
{
if
cc
.
singleUse
&&
cc
.
nextStreamID
>
1
{
return
false
}
return
cc
.
goAway
==
nil
&&
!
cc
.
closed
&&
int64
(
len
(
cc
.
streams
)
+
1
)
<
int64
(
cc
.
maxConcurrentStreams
)
&&
cc
.
nextStreamID
<
2147483647
...
...
@@ -578,6 +627,33 @@ func checkConnHeaders(req *http.Request) error {
return
nil
}
func
bodyAndLength
(
req
*
http
.
Request
)
(
body
io
.
Reader
,
contentLen
int64
)
{
body
=
req
.
Body
if
body
==
nil
{
return
nil
,
0
}
if
req
.
ContentLength
!=
0
{
return
req
.
Body
,
req
.
ContentLength
}
// We have a body but a zero content length. Test to see if
// it's actually zero or just unset.
var
buf
[
1
]
byte
n
,
rerr
:=
io
.
ReadFull
(
body
,
buf
[
:
])
if
rerr
!=
nil
&&
rerr
!=
io
.
EOF
{
return
errorReader
{
rerr
},
-
1
}
if
n
==
1
{
// Oh, guess there is data in this Body Reader after all.
// The ContentLength field just wasn't set.
// Stich the Body back together again, re-attaching our
// consumed byte.
return
io
.
MultiReader
(
bytes
.
NewReader
(
buf
[
:
]),
body
),
-
1
}
// Body is actually zero bytes.
return
nil
,
0
}
func
(
cc
*
ClientConn
)
RoundTrip
(
req
*
http
.
Request
)
(
*
http
.
Response
,
error
)
{
if
err
:=
checkConnHeaders
(
req
);
err
!=
nil
{
return
nil
,
err
...
...
@@ -589,39 +665,18 @@ func (cc *ClientConn) RoundTrip(req *http.Request) (*http.Response, error) {
}
hasTrailers
:=
trailers
!=
""
var
body
io
.
Reader
=
req
.
Body
contentLen
:=
req
.
ContentLength
if
req
.
Body
!=
nil
&&
contentLen
==
0
{
// Test to see if it's actually zero or just unset.
var
buf
[
1
]
byte
n
,
rerr
:=
io
.
ReadFull
(
body
,
buf
[
:
])
if
rerr
!=
nil
&&
rerr
!=
io
.
EOF
{
contentLen
=
-
1
body
=
errorReader
{
rerr
}
}
else
if
n
==
1
{
// Oh, guess there is data in this Body Reader after all.
// The ContentLength field just wasn't set.
// Stich the Body back together again, re-attaching our
// consumed byte.
contentLen
=
-
1
body
=
io
.
MultiReader
(
bytes
.
NewReader
(
buf
[
:
]),
body
)
}
else
{
// Body is actually empty.
body
=
nil
}
}
body
,
contentLen
:=
bodyAndLength
(
req
)
hasBody
:=
body
!=
nil
cc
.
mu
.
Lock
()
cc
.
lastActive
=
time
.
Now
()
if
cc
.
closed
||
!
cc
.
canTakeNewRequestLocked
()
{
cc
.
mu
.
Unlock
()
return
nil
,
errClientConnUnusable
}
cs
:=
cc
.
newStream
()
cs
.
req
=
req
hasBody
:=
body
!=
nil
// TODO(bradfitz): this is a copy of the logic in net/http. Unify somewhere?
var
requestedGzip
bool
if
!
cc
.
t
.
disableCompression
()
&&
req
.
Header
.
Get
(
"Accept-Encoding"
)
==
""
&&
req
.
Header
.
Get
(
"Range"
)
==
""
&&
...
...
@@ -638,37 +693,49 @@ func (cc *ClientConn) RoundTrip(req *http.Request) (*http.Response, error) {
// We don't request gzip if the request is for a range, since
// auto-decoding a portion of a gzipped document will just fail
// anyway. See https://golang.org/issue/8923
cs
.
requestedGzip
=
true
requestedGzip
=
true
}
// we send: HEADERS{1}, CONTINUATION{0,} + DATA{0,} (DATA is
// sent by writeRequestBody below, along with any Trailers,
// again in form HEADERS{1}, CONTINUATION{0,})
hdrs
:=
cc
.
encodeHeaders
(
req
,
cs
.
requestedGzip
,
trailers
,
contentLen
)
hdrs
,
err
:=
cc
.
encodeHeaders
(
req
,
requestedGzip
,
trailers
,
contentLen
)
if
err
!=
nil
{
cc
.
mu
.
Unlock
()
return
nil
,
err
}
cs
:=
cc
.
newStream
()
cs
.
req
=
req
cs
.
trace
=
requestTrace
(
req
)
cs
.
requestedGzip
=
requestedGzip
bodyWriter
:=
cc
.
t
.
getBodyWriterState
(
cs
,
body
)
cs
.
on100
=
bodyWriter
.
on100
cc
.
wmu
.
Lock
()
endStream
:=
!
hasBody
&&
!
hasTrailers
werr
:=
cc
.
writeHeaders
(
cs
.
ID
,
endStream
,
hdrs
)
cc
.
wmu
.
Unlock
()
traceWroteHeaders
(
cs
.
trace
)
cc
.
mu
.
Unlock
()
if
werr
!=
nil
{
if
hasBody
{
req
.
Body
.
Close
()
// per RoundTripper contract
bodyWriter
.
cancel
()
}
cc
.
forgetStreamID
(
cs
.
ID
)
// Don't bother sending a RST_STREAM (our write already failed;
// no need to keep writing)
traceWroteRequest
(
cs
.
trace
,
werr
)
return
nil
,
werr
}
var
respHeaderTimer
<-
chan
time
.
Time
var
bodyCopyErrc
chan
error
// result of body copy
if
hasBody
{
bodyCopyErrc
=
make
(
chan
error
,
1
)
go
func
()
{
bodyCopyErrc
<-
cs
.
writeRequestBody
(
body
,
req
.
Body
)
}()
bodyWriter
.
scheduleBodyWrite
()
}
else
{
traceWroteRequest
(
cs
.
trace
,
nil
)
if
d
:=
cc
.
responseHeaderTimeout
();
d
!=
0
{
timer
:=
time
.
NewTimer
(
d
)
defer
timer
.
Stop
()
...
...
@@ -677,8 +744,8 @@ func (cc *ClientConn) RoundTrip(req *http.Request) (*http.Response, error) {
}
readLoopResCh
:=
cs
.
resc
requestCanceledCh
:=
requestCancel
(
req
)
bodyWritten
:=
false
ctx
:=
reqContext
(
req
)
for
{
select
{
...
...
@@ -694,6 +761,7 @@ func (cc *ClientConn) RoundTrip(req *http.Request) (*http.Response, error) {
// doesn't, they'll RST_STREAM us soon enough. This is a
// heuristic to avoid adding knobs to Transport. Hopefully
// we can keep it.
bodyWriter
.
cancel
()
cs
.
abortRequestBodyWrite
(
errStopReqBodyWrite
)
}
if
re
.
err
!=
nil
{
...
...
@@ -708,14 +776,25 @@ func (cc *ClientConn) RoundTrip(req *http.Request) (*http.Response, error) {
if
!
hasBody
||
bodyWritten
{
cc
.
writeStreamReset
(
cs
.
ID
,
ErrCodeCancel
,
nil
)
}
else
{
bodyWriter
.
cancel
()
cs
.
abortRequestBodyWrite
(
errStopReqBodyWriteAndCancel
)
}
return
nil
,
errTimeout
case
<-
requestCanceledCh
:
case
<-
ctx
.
Done
()
:
cc
.
forgetStreamID
(
cs
.
ID
)
if
!
hasBody
||
bodyWritten
{
cc
.
writeStreamReset
(
cs
.
ID
,
ErrCodeCancel
,
nil
)
}
else
{
bodyWriter
.
cancel
()
cs
.
abortRequestBodyWrite
(
errStopReqBodyWriteAndCancel
)
}
return
nil
,
ctx
.
Err
()
case
<-
req
.
Cancel
:
cc
.
forgetStreamID
(
cs
.
ID
)
if
!
hasBody
||
bodyWritten
{
cc
.
writeStreamReset
(
cs
.
ID
,
ErrCodeCancel
,
nil
)
}
else
{
bodyWriter
.
cancel
()
cs
.
abortRequestBodyWrite
(
errStopReqBodyWriteAndCancel
)
}
return
nil
,
errRequestCanceled
...
...
@@ -724,7 +803,7 @@ func (cc *ClientConn) RoundTrip(req *http.Request) (*http.Response, error) {
// stream from the streams map; no need for
// forgetStreamID.
return
nil
,
cs
.
resetErr
case
err
:=
<-
body
CopyErr
c
:
case
err
:=
<-
body
Writer
.
res
c
:
if
err
!=
nil
{
return
nil
,
err
}
...
...
@@ -785,6 +864,7 @@ func (cs *clientStream) writeRequestBody(body io.Reader, bodyCloser io.Closer) (
defer
cc
.
putFrameScratchBuffer
(
buf
)
defer
func
()
{
traceWroteRequest
(
cs
.
trace
,
err
)
// TODO: write h12Compare test showing whether
// Request.Body is closed by the Transport,
// and in multiple cases: server replies <=299 and >299
...
...
@@ -881,7 +961,7 @@ func (cs *clientStream) awaitFlowControl(maxBytes int) (taken int32, err error)
if
cs
.
stopReqBody
!=
nil
{
return
0
,
cs
.
stopReqBody
}
if
err
:=
cs
.
checkReset
();
err
!=
nil
{
if
err
:=
cs
.
checkReset
OrDone
();
err
!=
nil
{
return
0
,
err
}
if
a
:=
cs
.
flow
.
available
();
a
>
0
{
...
...
@@ -908,7 +988,7 @@ type badStringError struct {
func
(
e
*
badStringError
)
Error
()
string
{
return
fmt
.
Sprintf
(
"%s %q"
,
e
.
what
,
e
.
str
)
}
// requires cc.mu be held.
func
(
cc
*
ClientConn
)
encodeHeaders
(
req
*
http
.
Request
,
addGzipHeader
bool
,
trailers
string
,
contentLength
int64
)
[]
byte
{
func
(
cc
*
ClientConn
)
encodeHeaders
(
req
*
http
.
Request
,
addGzipHeader
bool
,
trailers
string
,
contentLength
int64
)
([]
byte
,
error
)
{
cc
.
hbuf
.
Reset
()
host
:=
req
.
Host
...
...
@@ -916,6 +996,20 @@ func (cc *ClientConn) encodeHeaders(req *http.Request, addGzipHeader bool, trail
host
=
req
.
URL
.
Host
}
// Check for any invalid headers and return an error before we
// potentially pollute our hpack state. (We want to be able to
// continue to reuse the hpack encoder for future requests)
for
k
,
vv
:=
range
req
.
Header
{
if
!
httplex
.
ValidHeaderFieldName
(
k
)
{
return
nil
,
fmt
.
Errorf
(
"invalid HTTP header name %q"
,
k
)
}
for
_
,
v
:=
range
vv
{
if
!
httplex
.
ValidHeaderFieldValue
(
v
)
{
return
nil
,
fmt
.
Errorf
(
"invalid HTTP header value %q for header %q"
,
v
,
k
)
}
}
}
// 8.1.2.3 Request Pseudo-Header Fields
// The :path pseudo-header field includes the path and query parts of the
// target URI (the path-absolute production and optionally a '?' character
...
...
@@ -939,14 +1033,11 @@ func (cc *ClientConn) encodeHeaders(req *http.Request, addGzipHeader bool, trail
// Host is :authority, already sent.
// Content-Length is automatic, set below.
continue
case
"connection"
,
"proxy-connection"
,
"transfer-encoding"
,
"upgrade"
:
case
"connection"
,
"proxy-connection"
,
"transfer-encoding"
,
"upgrade"
,
"keep-alive"
:
// Per 8.1.2.2 Connection-Specific Header
// Fields, don't send connection-specific
// fields. We deal with these earlier in
// RoundTrip, deciding whether they're
// error-worthy, but we don't want to mutate
// the user's *Request so at this point, just
// skip over them at this point.
// fields. We have already checked if any
// are error-worthy so just ignore the rest.
continue
case
"user-agent"
:
// Match Go's http1 behavior: at most one
...
...
@@ -975,7 +1066,7 @@ func (cc *ClientConn) encodeHeaders(req *http.Request, addGzipHeader bool, trail
if
!
didUA
{
cc
.
writeHeader
(
"user-agent"
,
defaultUserAgent
)
}
return
cc
.
hbuf
.
Bytes
()
return
cc
.
hbuf
.
Bytes
()
,
nil
}
// shouldSendReqContentLength reports whether the http2.Transport should send
...
...
@@ -1053,8 +1144,10 @@ func (cc *ClientConn) streamByID(id uint32, andRemove bool) *clientStream {
defer
cc
.
mu
.
Unlock
()
cs
:=
cc
.
streams
[
id
]
if
andRemove
&&
cs
!=
nil
&&
!
cc
.
closed
{
cc
.
lastActive
=
time
.
Now
()
delete
(
cc
.
streams
,
id
)
close
(
cs
.
done
)
cc
.
cond
.
Broadcast
()
// wake up checkResetOrDone via clientStream.awaitFlowControl
}
return
cs
}
...
...
@@ -1064,15 +1157,6 @@ type clientConnReadLoop struct {
cc
*
ClientConn
activeRes
map
[
uint32
]
*
clientStream
// keyed by streamID
closeWhenIdle
bool
hdec
*
hpack
.
Decoder
// Fields reset on each HEADERS:
nextRes
*
http
.
Response
sawRegHeader
bool
// saw non-pseudo header
reqMalformed
error
// non-nil once known to be malformed
lastHeaderEndsStream
bool
headerListSize
int64
// actually uint32, but easier math this way
}
// readLoop runs in its own goroutine and reads and dispatches frames.
...
...
@@ -1081,7 +1165,6 @@ func (cc *ClientConn) readLoop() {
cc
:
cc
,
activeRes
:
make
(
map
[
uint32
]
*
clientStream
),
}
rl
.
hdec
=
hpack
.
NewDecoder
(
initialHeaderTableSize
,
rl
.
onNewHeaderField
)
defer
rl
.
cleanup
()
cc
.
readerErr
=
rl
.
run
()
...
...
@@ -1092,6 +1175,19 @@ func (cc *ClientConn) readLoop() {
}
}
// GoAwayError is returned by the Transport when the server closes the
// TCP connection after sending a GOAWAY frame.
type
GoAwayError
struct
{
LastStreamID
uint32
ErrCode
ErrCode
DebugData
string
}
func
(
e
GoAwayError
)
Error
()
string
{
return
fmt
.
Sprintf
(
"http2: server sent GOAWAY and closed the connection; LastStreamID=%v, ErrCode=%v, debug=%q"
,
e
.
LastStreamID
,
e
.
ErrCode
,
e
.
DebugData
)
}
func
(
rl
*
clientConnReadLoop
)
cleanup
()
{
cc
:=
rl
.
cc
defer
cc
.
tconn
.
Close
()
...
...
@@ -1102,10 +1198,18 @@ func (rl *clientConnReadLoop) cleanup() {
// TODO: also do this if we've written the headers but not
// gotten a response yet.
err
:=
cc
.
readerErr
cc
.
mu
.
Lock
()
if
err
==
io
.
EOF
{
err
=
io
.
ErrUnexpectedEOF
if
cc
.
goAway
!=
nil
{
err
=
GoAwayError
{
LastStreamID
:
cc
.
goAway
.
LastStreamID
,
ErrCode
:
cc
.
goAway
.
ErrCode
,
DebugData
:
cc
.
goAwayDebug
,
}
}
else
{
err
=
io
.
ErrUnexpectedEOF
}
}
cc
.
mu
.
Lock
()
for
_
,
cs
:=
range
rl
.
activeRes
{
cs
.
bufPipe
.
CloseWithError
(
err
)
}
...
...
@@ -1123,7 +1227,7 @@ func (rl *clientConnReadLoop) cleanup() {
func
(
rl
*
clientConnReadLoop
)
run
()
error
{
cc
:=
rl
.
cc
rl
.
closeWhenIdle
=
cc
.
t
.
disableKeepAlives
()
rl
.
closeWhenIdle
=
cc
.
t
.
disableKeepAlives
()
||
cc
.
singleUse
gotReply
:=
false
// ever saw a reply
for
{
f
,
err
:=
cc
.
fr
.
ReadFrame
()
...
...
@@ -1131,8 +1235,10 @@ func (rl *clientConnReadLoop) run() error {
cc
.
vlogf
(
"Transport readFrame error: (%T) %v"
,
err
,
err
)
}
if
se
,
ok
:=
err
.
(
StreamError
);
ok
{
// TODO: deal with stream errors from the framer.
return
se
if
cs
:=
cc
.
streamByID
(
se
.
StreamID
,
true
/*ended; remove it*/
);
cs
!=
nil
{
rl
.
endStreamError
(
cs
,
cc
.
fr
.
errDetail
)
}
continue
}
else
if
err
!=
nil
{
return
err
}
...
...
@@ -1142,13 +1248,10 @@ func (rl *clientConnReadLoop) run() error {
maybeIdle
:=
false
// whether frame might transition us to idle
switch
f
:=
f
.
(
type
)
{
case
*
HeadersFrame
:
case
*
Meta
HeadersFrame
:
err
=
rl
.
processHeaders
(
f
)
maybeIdle
=
true
gotReply
=
true
case
*
ContinuationFrame
:
err
=
rl
.
processContinuation
(
f
)
maybeIdle
=
true
case
*
DataFrame
:
err
=
rl
.
processData
(
f
)
maybeIdle
=
true
...
...
@@ -1178,92 +1281,110 @@ func (rl *clientConnReadLoop) run() error {
}
}
func
(
rl
*
clientConnReadLoop
)
processHeaders
(
f
*
HeadersFrame
)
error
{
rl
.
sawRegHeader
=
false
rl
.
reqMalformed
=
nil
rl
.
lastHeaderEndsStream
=
f
.
StreamEnded
()
rl
.
headerListSize
=
0
rl
.
nextRes
=
&
http
.
Response
{
Proto
:
"HTTP/2.0"
,
ProtoMajor
:
2
,
Header
:
make
(
http
.
Header
),
}
rl
.
hdec
.
SetEmitEnabled
(
true
)
return
rl
.
processHeaderBlockFragment
(
f
.
HeaderBlockFragment
(),
f
.
StreamID
,
f
.
HeadersEnded
())
}
func
(
rl
*
clientConnReadLoop
)
processContinuation
(
f
*
ContinuationFrame
)
error
{
return
rl
.
processHeaderBlockFragment
(
f
.
HeaderBlockFragment
(),
f
.
StreamID
,
f
.
HeadersEnded
())
}
func
(
rl
*
clientConnReadLoop
)
processHeaderBlockFragment
(
frag
[]
byte
,
streamID
uint32
,
finalFrag
bool
)
error
{
func
(
rl
*
clientConnReadLoop
)
processHeaders
(
f
*
MetaHeadersFrame
)
error
{
cc
:=
rl
.
cc
streamEnded
:=
rl
.
lastHeaderEndsStream
cs
:=
cc
.
streamByID
(
streamID
,
streamEnded
&&
finalFrag
)
cs
:=
cc
.
streamByID
(
f
.
StreamID
,
f
.
StreamEnded
())
if
cs
==
nil
{
// We'd get here if we canceled a request while the
// server was mid-way through replying with its
// headers. (The case of a CONTINUATION arriving
// without HEADERS would be rejected earlier by the
// Framer). So if this was just something we canceled,
// ignore it.
// server had its response still in flight. So if this
// was just something we canceled, ignore it.
return
nil
}
if
cs
.
pastHeaders
{
rl
.
hdec
.
SetEmitFunc
(
func
(
f
hpack
.
HeaderField
)
{
rl
.
onNewTrailerField
(
cs
,
f
)
})
}
else
{
rl
.
hdec
.
SetEmitFunc
(
rl
.
onNewHeaderField
)
}
_
,
err
:=
rl
.
hdec
.
Write
(
frag
)
if
err
!=
nil
{
return
ConnectionError
(
ErrCodeCompression
)
}
if
finalFrag
{
if
err
:=
rl
.
hdec
.
Close
();
err
!=
nil
{
return
ConnectionError
(
ErrCodeCompression
)
if
!
cs
.
firstByte
{
if
cs
.
trace
!=
nil
{
// TODO(bradfitz): move first response byte earlier,
// when we first read the 9 byte header, not waiting
// until all the HEADERS+CONTINUATION frames have been
// merged. This works for now.
traceFirstResponseByte
(
cs
.
trace
)
}
cs
.
firstByte
=
true
}
if
!
finalFrag
{
return
nil
}
if
!
cs
.
pastHeaders
{
cs
.
pastHeaders
=
true
}
else
{
// We're dealing with trailers. (and specifically the
// final frame of headers)
if
cs
.
pastTrailers
{
// Too many HEADERS frames for this stream.
return
ConnectionError
(
ErrCodeProtocol
)
}
cs
.
pastTrailers
=
true
if
!
streamEnded
{
// We expect that any header block fragment
// frame for trailers with END_HEADERS also
// has END_STREAM.
return
ConnectionError
(
ErrCodeProtocol
)
return
rl
.
processTrailers
(
cs
,
f
)
}
res
,
err
:=
rl
.
handleResponse
(
cs
,
f
)
if
err
!=
nil
{
if
_
,
ok
:=
err
.
(
ConnectionError
);
ok
{
return
err
}
rl
.
endStream
(
cs
)
// Any other error type is a stream error.
cs
.
cc
.
writeStreamReset
(
f
.
StreamID
,
ErrCodeProtocol
,
err
)
cs
.
resc
<-
resAndError
{
err
:
err
}
return
nil
// return nil from process* funcs to keep conn alive
}
if
res
==
nil
{
// (nil, nil) special case. See handleResponse docs.
return
nil
}
if
res
.
Body
!=
noBody
{
rl
.
activeRes
[
cs
.
ID
]
=
cs
}
cs
.
resTrailer
=
&
res
.
Trailer
cs
.
resc
<-
resAndError
{
res
:
res
}
return
nil
}
if
rl
.
reqMalformed
!=
nil
{
cs
.
resc
<-
resAndError
{
err
:
rl
.
reqMalformed
}
rl
.
cc
.
writeStreamReset
(
cs
.
ID
,
ErrCodeProtocol
,
rl
.
reqMalformed
)
return
nil
// may return error types nil, or ConnectionError. Any other error value
// is a StreamError of type ErrCodeProtocol. The returned error in that case
// is the detail.
//
// As a special case, handleResponse may return (nil, nil) to skip the
// frame (currently only used for 100 expect continue). This special
// case is going away after Issue 13851 is fixed.
func
(
rl
*
clientConnReadLoop
)
handleResponse
(
cs
*
clientStream
,
f
*
MetaHeadersFrame
)
(
*
http
.
Response
,
error
)
{
if
f
.
Truncated
{
return
nil
,
errResponseHeaderListSize
}
res
:=
rl
.
nextRes
status
:=
f
.
PseudoValue
(
"status"
)
if
status
==
""
{
return
nil
,
errors
.
New
(
"missing status pseudo header"
)
}
statusCode
,
err
:=
strconv
.
Atoi
(
status
)
if
err
!=
nil
{
return
nil
,
errors
.
New
(
"malformed non-numeric status pseudo header"
)
}
if
res
.
StatusCode
==
100
{
// Just skip 100-continue response headers for now.
// TODO: golang.org/issue/13851 for doing it properly.
if
statusCode
==
100
{
traceGot100Continue
(
cs
.
trace
)
if
cs
.
on100
!=
nil
{
cs
.
on100
()
// forces any write delay timer to fire
}
cs
.
pastHeaders
=
false
// do it all again
return
nil
return
nil
,
nil
}
header
:=
make
(
http
.
Header
)
res
:=
&
http
.
Response
{
Proto
:
"HTTP/2.0"
,
ProtoMajor
:
2
,
Header
:
header
,
StatusCode
:
statusCode
,
Status
:
status
+
" "
+
http
.
StatusText
(
statusCode
),
}
for
_
,
hf
:=
range
f
.
RegularFields
()
{
key
:=
http
.
CanonicalHeaderKey
(
hf
.
Name
)
if
key
==
"Trailer"
{
t
:=
res
.
Trailer
if
t
==
nil
{
t
=
make
(
http
.
Header
)
res
.
Trailer
=
t
}
foreachHeaderElement
(
hf
.
Value
,
func
(
v
string
)
{
t
[
http
.
CanonicalHeaderKey
(
v
)]
=
nil
})
}
else
{
header
[
key
]
=
append
(
header
[
key
],
hf
.
Value
)
}
}
if
!
streamEnded
||
cs
.
req
.
Method
==
"HEAD"
{
streamEnded
:=
f
.
StreamEnded
()
isHead
:=
cs
.
req
.
Method
==
"HEAD"
if
!
streamEnded
||
isHead
{
res
.
ContentLength
=
-
1
if
clens
:=
res
.
Header
[
"Content-Length"
];
len
(
clens
)
==
1
{
if
clen64
,
err
:=
strconv
.
ParseInt
(
clens
[
0
],
10
,
64
);
err
==
nil
{
...
...
@@ -1278,27 +1399,52 @@ func (rl *clientConnReadLoop) processHeaderBlockFragment(frag []byte, streamID u
}
}
if
streamEnded
{
if
streamEnded
||
isHead
{
res
.
Body
=
noBody
}
else
{
buf
:=
new
(
bytes
.
Buffer
)
// TODO(bradfitz): recycle this garbage
cs
.
bufPipe
=
pipe
{
b
:
buf
}
cs
.
bytesRemain
=
res
.
ContentLength
res
.
Body
=
transportResponseBody
{
cs
}
go
cs
.
awaitRequestCancel
(
requestCancel
(
cs
.
req
))
if
cs
.
requestedGzip
&&
res
.
Header
.
Get
(
"Content-Encoding"
)
==
"gzip"
{
res
.
Header
.
Del
(
"Content-Encoding"
)
res
.
Header
.
Del
(
"Content-Length"
)
res
.
ContentLength
=
-
1
res
.
Body
=
&
gzipReader
{
body
:
res
.
Body
}
}
rl
.
activeRes
[
cs
.
ID
]
=
cs
return
res
,
nil
}
cs
.
resTrailer
=
&
res
.
Trailer
cs
.
resc
<-
resAndError
{
res
:
res
}
rl
.
nextRes
=
nil
// unused now; will be reset next HEADERS frame
buf
:=
new
(
bytes
.
Buffer
)
// TODO(bradfitz): recycle this garbage
cs
.
bufPipe
=
pipe
{
b
:
buf
}
cs
.
bytesRemain
=
res
.
ContentLength
res
.
Body
=
transportResponseBody
{
cs
}
go
cs
.
awaitRequestCancel
(
cs
.
req
)
if
cs
.
requestedGzip
&&
res
.
Header
.
Get
(
"Content-Encoding"
)
==
"gzip"
{
res
.
Header
.
Del
(
"Content-Encoding"
)
res
.
Header
.
Del
(
"Content-Length"
)
res
.
ContentLength
=
-
1
res
.
Body
=
&
gzipReader
{
body
:
res
.
Body
}
setResponseUncompressed
(
res
)
}
return
res
,
nil
}
func
(
rl
*
clientConnReadLoop
)
processTrailers
(
cs
*
clientStream
,
f
*
MetaHeadersFrame
)
error
{
if
cs
.
pastTrailers
{
// Too many HEADERS frames for this stream.
return
ConnectionError
(
ErrCodeProtocol
)
}
cs
.
pastTrailers
=
true
if
!
f
.
StreamEnded
()
{
// We expect that any headers for trailers also
// has END_STREAM.
return
ConnectionError
(
ErrCodeProtocol
)
}
if
len
(
f
.
PseudoFields
())
>
0
{
// No pseudo header fields are defined for trailers.
// TODO: ConnectionError might be overly harsh? Check.
return
ConnectionError
(
ErrCodeProtocol
)
}
trailer
:=
make
(
http
.
Header
)
for
_
,
hf
:=
range
f
.
RegularFields
()
{
key
:=
http
.
CanonicalHeaderKey
(
hf
.
Name
)
trailer
[
key
]
=
append
(
trailer
[
key
],
hf
.
Value
)
}
cs
.
trailer
=
trailer
rl
.
endStream
(
cs
)
return
nil
}
...
...
@@ -1349,8 +1495,12 @@ func (b transportResponseBody) Read(p []byte) (n int, err error) {
cc
.
inflow
.
add
(
connAdd
)
}
if
err
==
nil
{
// No need to refresh if the stream is over or failed.
if
v
:=
cs
.
inflow
.
available
();
v
<
transportDefaultStreamFlow
-
transportDefaultStreamMinRefresh
{
streamAdd
=
transportDefaultStreamFlow
-
v
// Consider any buffered body data (read from the conn but not
// consumed by the client) when computing flow control for this
// stream.
v
:=
int
(
cs
.
inflow
.
available
())
+
cs
.
bufPipe
.
Len
()
if
v
<
transportDefaultStreamFlow
-
transportDefaultStreamMinRefresh
{
streamAdd
=
int32
(
transportDefaultStreamFlow
-
v
)
cs
.
inflow
.
add
(
streamAdd
)
}
}
...
...
@@ -1416,6 +1566,7 @@ func (rl *clientConnReadLoop) processData(f *DataFrame) error {
cc
.
mu
.
Unlock
()
if
_
,
err
:=
cs
.
bufPipe
.
Write
(
data
);
err
!=
nil
{
rl
.
endStreamError
(
cs
,
err
)
return
err
}
}
...
...
@@ -1431,11 +1582,14 @@ var errInvalidTrailers = errors.New("http2: invalid trailers")
func
(
rl
*
clientConnReadLoop
)
endStream
(
cs
*
clientStream
)
{
// TODO: check that any declared content-length matches, like
// server.go's (*stream).endStream method.
err
:=
io
.
EOF
code
:=
cs
.
copyTrailers
if
rl
.
reqMalformed
!=
nil
{
err
=
rl
.
reqMalformed
code
=
nil
rl
.
endStreamError
(
cs
,
nil
)
}
func
(
rl
*
clientConnReadLoop
)
endStreamError
(
cs
*
clientStream
,
err
error
)
{
var
code
func
()
if
err
==
nil
{
err
=
io
.
EOF
code
=
cs
.
copyTrailers
}
cs
.
bufPipe
.
closeWithErrorAndCode
(
err
,
code
)
delete
(
rl
.
activeRes
,
cs
.
ID
)
...
...
@@ -1528,7 +1682,7 @@ func (rl *clientConnReadLoop) processResetStream(f *RSTStreamFrame) error {
cs
.
resetErr
=
err
close
(
cs
.
peerReset
)
cs
.
bufPipe
.
CloseWithError
(
err
)
cs
.
cc
.
cond
.
Broadcast
()
// wake up checkReset via clientStream.awaitFlowControl
cs
.
cc
.
cond
.
Broadcast
()
// wake up checkReset
OrDone
via clientStream.awaitFlowControl
}
delete
(
rl
.
activeRes
,
cs
.
ID
)
return
nil
...
...
@@ -1574,118 +1728,6 @@ var (
errPseudoTrailers
=
errors
.
New
(
"http2: invalid pseudo header in trailers"
)
)
func
(
rl
*
clientConnReadLoop
)
checkHeaderField
(
f
hpack
.
HeaderField
)
bool
{
if
rl
.
reqMalformed
!=
nil
{
return
false
}
const
headerFieldOverhead
=
32
// per spec
rl
.
headerListSize
+=
int64
(
len
(
f
.
Name
))
+
int64
(
len
(
f
.
Value
))
+
headerFieldOverhead
if
max
:=
rl
.
cc
.
t
.
maxHeaderListSize
();
max
!=
0
&&
rl
.
headerListSize
>
int64
(
max
)
{
rl
.
hdec
.
SetEmitEnabled
(
false
)
rl
.
reqMalformed
=
errResponseHeaderListSize
return
false
}
if
!
validHeaderFieldValue
(
f
.
Value
)
{
rl
.
reqMalformed
=
errInvalidHeaderFieldValue
return
false
}
isPseudo
:=
strings
.
HasPrefix
(
f
.
Name
,
":"
)
if
isPseudo
{
if
rl
.
sawRegHeader
{
rl
.
reqMalformed
=
errors
.
New
(
"http2: invalid pseudo header after regular header"
)
return
false
}
}
else
{
if
!
validHeaderFieldName
(
f
.
Name
)
{
rl
.
reqMalformed
=
errInvalidHeaderFieldName
return
false
}
rl
.
sawRegHeader
=
true
}
return
true
}
// onNewHeaderField runs on the readLoop goroutine whenever a new
// hpack header field is decoded.
func
(
rl
*
clientConnReadLoop
)
onNewHeaderField
(
f
hpack
.
HeaderField
)
{
cc
:=
rl
.
cc
if
VerboseLogs
{
cc
.
logf
(
"http2: Transport decoded %v"
,
f
)
}
if
!
rl
.
checkHeaderField
(
f
)
{
return
}
isPseudo
:=
strings
.
HasPrefix
(
f
.
Name
,
":"
)
if
isPseudo
{
switch
f
.
Name
{
case
":status"
:
code
,
err
:=
strconv
.
Atoi
(
f
.
Value
)
if
err
!=
nil
{
rl
.
reqMalformed
=
errors
.
New
(
"http2: invalid :status"
)
return
}
rl
.
nextRes
.
Status
=
f
.
Value
+
" "
+
http
.
StatusText
(
code
)
rl
.
nextRes
.
StatusCode
=
code
default
:
// "Endpoints MUST NOT generate pseudo-header
// fields other than those defined in this
// document."
rl
.
reqMalformed
=
fmt
.
Errorf
(
"http2: unknown response pseudo header %q"
,
f
.
Name
)
}
return
}
key
:=
http
.
CanonicalHeaderKey
(
f
.
Name
)
if
key
==
"Trailer"
{
t
:=
rl
.
nextRes
.
Trailer
if
t
==
nil
{
t
=
make
(
http
.
Header
)
rl
.
nextRes
.
Trailer
=
t
}
foreachHeaderElement
(
f
.
Value
,
func
(
v
string
)
{
t
[
http
.
CanonicalHeaderKey
(
v
)]
=
nil
})
}
else
{
rl
.
nextRes
.
Header
.
Add
(
key
,
f
.
Value
)
}
}
func
(
rl
*
clientConnReadLoop
)
onNewTrailerField
(
cs
*
clientStream
,
f
hpack
.
HeaderField
)
{
if
VerboseLogs
{
rl
.
cc
.
logf
(
"http2: Transport decoded trailer %v"
,
f
)
}
if
!
rl
.
checkHeaderField
(
f
)
{
return
}
if
strings
.
HasPrefix
(
f
.
Name
,
":"
)
{
// Pseudo-header fields MUST NOT appear in
// trailers. Endpoints MUST treat a request or
// response that contains undefined or invalid
// pseudo-header fields as malformed.
rl
.
reqMalformed
=
errPseudoTrailers
return
}
key
:=
http
.
CanonicalHeaderKey
(
f
.
Name
)
// The spec says one must predeclare their trailers but in practice
// popular users (which is to say the only user we found) do not so we
// violate the spec and accept all of them.
const
acceptAllTrailers
=
true
if
_
,
ok
:=
(
*
cs
.
resTrailer
)[
key
];
ok
||
acceptAllTrailers
{
if
cs
.
trailer
==
nil
{
cs
.
trailer
=
make
(
http
.
Header
)
}
cs
.
trailer
[
key
]
=
append
(
cs
.
trailer
[
key
],
f
.
Value
)
}
}
func
(
cc
*
ClientConn
)
logf
(
format
string
,
args
...
interface
{})
{
cc
.
t
.
logf
(
format
,
args
...
)
}
...
...
@@ -1748,3 +1790,79 @@ func (gz *gzipReader) Close() error {
type
errorReader
struct
{
err
error
}
func
(
r
errorReader
)
Read
(
p
[]
byte
)
(
int
,
error
)
{
return
0
,
r
.
err
}
// bodyWriterState encapsulates various state around the Transport's writing
// of the request body, particularly regarding doing delayed writes of the body
// when the request contains "Expect: 100-continue".
type
bodyWriterState
struct
{
cs
*
clientStream
timer
*
time
.
Timer
// if non-nil, we're doing a delayed write
fnonce
*
sync
.
Once
// to call fn with
fn
func
()
// the code to run in the goroutine, writing the body
resc
chan
error
// result of fn's execution
delay
time
.
Duration
// how long we should delay a delayed write for
}
func
(
t
*
Transport
)
getBodyWriterState
(
cs
*
clientStream
,
body
io
.
Reader
)
(
s
bodyWriterState
)
{
s
.
cs
=
cs
if
body
==
nil
{
return
}
resc
:=
make
(
chan
error
,
1
)
s
.
resc
=
resc
s
.
fn
=
func
()
{
resc
<-
cs
.
writeRequestBody
(
body
,
cs
.
req
.
Body
)
}
s
.
delay
=
t
.
expectContinueTimeout
()
if
s
.
delay
==
0
||
!
httplex
.
HeaderValuesContainsToken
(
cs
.
req
.
Header
[
"Expect"
],
"100-continue"
)
{
return
}
s
.
fnonce
=
new
(
sync
.
Once
)
// Arm the timer with a very large duration, which we'll
// intentionally lower later. It has to be large now because
// we need a handle to it before writing the headers, but the
// s.delay value is defined to not start until after the
// request headers were written.
const
hugeDuration
=
365
*
24
*
time
.
Hour
s
.
timer
=
time
.
AfterFunc
(
hugeDuration
,
func
()
{
s
.
fnonce
.
Do
(
s
.
fn
)
})
return
}
func
(
s
bodyWriterState
)
cancel
()
{
if
s
.
timer
!=
nil
{
s
.
timer
.
Stop
()
}
}
func
(
s
bodyWriterState
)
on100
()
{
if
s
.
timer
==
nil
{
// If we didn't do a delayed write, ignore the server's
// bogus 100 continue response.
return
}
s
.
timer
.
Stop
()
go
func
()
{
s
.
fnonce
.
Do
(
s
.
fn
)
}()
}
// scheduleBodyWrite starts writing the body, either immediately (in
// the common case) or after the delay timeout. It should not be
// called until after the headers have been written.
func
(
s
bodyWriterState
)
scheduleBodyWrite
()
{
if
s
.
timer
==
nil
{
// We're not doing a delayed write (see
// getBodyWriterState), so just start the writing
// goroutine immediately.
go
s
.
fn
()
return
}
traceWait100Continue
(
s
.
cs
.
trace
)
if
s
.
timer
.
Stop
()
{
s
.
timer
.
Reset
(
s
.
delay
)
}
}
vendor/golang.org/x/net/http2/write.go
View file @
e5ed62e8
...
...
@@ -9,10 +9,10 @@ import (
"fmt"
"log"
"net/http"
"sort"
"time"
"golang.org/x/net/http2/hpack"
"golang.org/x/net/lex/httplex"
)
// writeFramer is implemented by any type that is used to write frames.
...
...
@@ -230,25 +230,26 @@ func (wu writeWindowUpdate) writeFrame(ctx writeContext) error {
}
func
encodeHeaders
(
enc
*
hpack
.
Encoder
,
h
http
.
Header
,
keys
[]
string
)
{
// TODO: garbage. pool sorters like http1? hot path for 1 key?
if
keys
==
nil
{
keys
=
make
([]
string
,
0
,
len
(
h
))
for
k
:=
range
h
{
keys
=
append
(
keys
,
k
)
}
sort
.
Strings
(
keys
)
sorter
:=
sorterPool
.
Get
()
.
(
*
sorter
)
// Using defer here, since the returned keys from the
// sorter.Keys method is only valid until the sorter
// is returned:
defer
sorterPool
.
Put
(
sorter
)
keys
=
sorter
.
Keys
(
h
)
}
for
_
,
k
:=
range
keys
{
vv
:=
h
[
k
]
k
=
lowerHeader
(
k
)
if
!
validHeaderFieldName
(
k
)
{
// TODO: return an error? golang.org/issue/14048
// For now just omit it.
if
!
validWireHeaderFieldName
(
k
)
{
// Skip it as backup paranoia. Per
// golang.org/issue/14048, these should
// already be rejected at a higher level.
continue
}
isTE
:=
k
==
"transfer-encoding"
for
_
,
v
:=
range
vv
{
if
!
v
alidHeaderFieldValue
(
v
)
{
if
!
httplex
.
V
alidHeaderFieldValue
(
v
)
{
// TODO: return an error? golang.org/issue/14048
// For now just omit it.
continue
...
...
vendor/golang.org/x/net/lex/httplex/httplex.go
0 → 100644
View file @
e5ed62e8
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package httplex contains rules around lexical matters of various
// HTTP-related specifications.
//
// This package is shared by the standard library (which vendors it)
// and x/net/http2. It comes with no API stability promise.
package
httplex
import
(
"strings"
"unicode/utf8"
)
var
isTokenTable
=
[
127
]
bool
{
'!'
:
true
,
'#'
:
true
,
'$'
:
true
,
'%'
:
true
,
'&'
:
true
,
'\'
'
:
true
,
'*'
:
true
,
'+'
:
true
,
'-'
:
true
,
'.'
:
true
,
'0'
:
true
,
'1'
:
true
,
'2'
:
true
,
'3'
:
true
,
'4'
:
true
,
'5'
:
true
,
'6'
:
true
,
'7'
:
true
,
'8'
:
true
,
'9'
:
true
,
'A'
:
true
,
'B'
:
true
,
'C'
:
true
,
'D'
:
true
,
'E'
:
true
,
'F'
:
true
,
'G'
:
true
,
'H'
:
true
,
'I'
:
true
,
'J'
:
true
,
'K'
:
true
,
'L'
:
true
,
'M'
:
true
,
'N'
:
true
,
'O'
:
true
,
'P'
:
true
,
'Q'
:
true
,
'R'
:
true
,
'S'
:
true
,
'T'
:
true
,
'U'
:
true
,
'W'
:
true
,
'V'
:
true
,
'X'
:
true
,
'Y'
:
true
,
'Z'
:
true
,
'^'
:
true
,
'_'
:
true
,
'`'
:
true
,
'a'
:
true
,
'b'
:
true
,
'c'
:
true
,
'd'
:
true
,
'e'
:
true
,
'f'
:
true
,
'g'
:
true
,
'h'
:
true
,
'i'
:
true
,
'j'
:
true
,
'k'
:
true
,
'l'
:
true
,
'm'
:
true
,
'n'
:
true
,
'o'
:
true
,
'p'
:
true
,
'q'
:
true
,
'r'
:
true
,
's'
:
true
,
't'
:
true
,
'u'
:
true
,
'v'
:
true
,
'w'
:
true
,
'x'
:
true
,
'y'
:
true
,
'z'
:
true
,
'|'
:
true
,
'~'
:
true
,
}
func
IsTokenRune
(
r
rune
)
bool
{
i
:=
int
(
r
)
return
i
<
len
(
isTokenTable
)
&&
isTokenTable
[
i
]
}
func
isNotToken
(
r
rune
)
bool
{
return
!
IsTokenRune
(
r
)
}
// HeaderValuesContainsToken reports whether any string in values
// contains the provided token, ASCII case-insensitively.
func
HeaderValuesContainsToken
(
values
[]
string
,
token
string
)
bool
{
for
_
,
v
:=
range
values
{
if
headerValueContainsToken
(
v
,
token
)
{
return
true
}
}
return
false
}
// isOWS reports whether b is an optional whitespace byte, as defined
// by RFC 7230 section 3.2.3.
func
isOWS
(
b
byte
)
bool
{
return
b
==
' '
||
b
==
'\t'
}
// trimOWS returns x with all optional whitespace removes from the
// beginning and end.
func
trimOWS
(
x
string
)
string
{
// TODO: consider using strings.Trim(x, " \t") instead,
// if and when it's fast enough. See issue 10292.
// But this ASCII-only code will probably always beat UTF-8
// aware code.
for
len
(
x
)
>
0
&&
isOWS
(
x
[
0
])
{
x
=
x
[
1
:
]
}
for
len
(
x
)
>
0
&&
isOWS
(
x
[
len
(
x
)
-
1
])
{
x
=
x
[
:
len
(
x
)
-
1
]
}
return
x
}
// headerValueContainsToken reports whether v (assumed to be a
// 0#element, in the ABNF extension described in RFC 7230 section 7)
// contains token amongst its comma-separated tokens, ASCII
// case-insensitively.
func
headerValueContainsToken
(
v
string
,
token
string
)
bool
{
v
=
trimOWS
(
v
)
if
comma
:=
strings
.
IndexByte
(
v
,
','
);
comma
!=
-
1
{
return
tokenEqual
(
trimOWS
(
v
[
:
comma
]),
token
)
||
headerValueContainsToken
(
v
[
comma
+
1
:
],
token
)
}
return
tokenEqual
(
v
,
token
)
}
// lowerASCII returns the ASCII lowercase version of b.
func
lowerASCII
(
b
byte
)
byte
{
if
'A'
<=
b
&&
b
<=
'Z'
{
return
b
+
(
'a'
-
'A'
)
}
return
b
}
// tokenEqual reports whether t1 and t2 are equal, ASCII case-insensitively.
func
tokenEqual
(
t1
,
t2
string
)
bool
{
if
len
(
t1
)
!=
len
(
t2
)
{
return
false
}
for
i
,
b
:=
range
t1
{
if
b
>=
utf8
.
RuneSelf
{
// No UTF-8 or non-ASCII allowed in tokens.
return
false
}
if
lowerASCII
(
byte
(
b
))
!=
lowerASCII
(
t2
[
i
])
{
return
false
}
}
return
true
}
// isLWS reports whether b is linear white space, according
// to http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2.2
// LWS = [CRLF] 1*( SP | HT )
func
isLWS
(
b
byte
)
bool
{
return
b
==
' '
||
b
==
'\t'
}
// isCTL reports whether b is a control byte, according
// to http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2.2
// CTL = <any US-ASCII control character
// (octets 0 - 31) and DEL (127)>
func
isCTL
(
b
byte
)
bool
{
const
del
=
0x7f
// a CTL
return
b
<
' '
||
b
==
del
}
// ValidHeaderFieldName reports whether v is a valid HTTP/1.x header name.
// HTTP/2 imposes the additional restriction that uppercase ASCII
// letters are not allowed.
//
// RFC 7230 says:
// header-field = field-name ":" OWS field-value OWS
// field-name = token
// token = 1*tchar
// tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "." /
// "^" / "_" / "`" / "|" / "~" / DIGIT / ALPHA
func
ValidHeaderFieldName
(
v
string
)
bool
{
if
len
(
v
)
==
0
{
return
false
}
for
_
,
r
:=
range
v
{
if
!
IsTokenRune
(
r
)
{
return
false
}
}
return
true
}
// ValidHostHeader reports whether h is a valid host header.
func
ValidHostHeader
(
h
string
)
bool
{
// The latest spec is actually this:
//
// http://tools.ietf.org/html/rfc7230#section-5.4
// Host = uri-host [ ":" port ]
//
// Where uri-host is:
// http://tools.ietf.org/html/rfc3986#section-3.2.2
//
// But we're going to be much more lenient for now and just
// search for any byte that's not a valid byte in any of those
// expressions.
for
i
:=
0
;
i
<
len
(
h
);
i
++
{
if
!
validHostByte
[
h
[
i
]]
{
return
false
}
}
return
true
}
// See the validHostHeader comment.
var
validHostByte
=
[
256
]
bool
{
'0'
:
true
,
'1'
:
true
,
'2'
:
true
,
'3'
:
true
,
'4'
:
true
,
'5'
:
true
,
'6'
:
true
,
'7'
:
true
,
'8'
:
true
,
'9'
:
true
,
'a'
:
true
,
'b'
:
true
,
'c'
:
true
,
'd'
:
true
,
'e'
:
true
,
'f'
:
true
,
'g'
:
true
,
'h'
:
true
,
'i'
:
true
,
'j'
:
true
,
'k'
:
true
,
'l'
:
true
,
'm'
:
true
,
'n'
:
true
,
'o'
:
true
,
'p'
:
true
,
'q'
:
true
,
'r'
:
true
,
's'
:
true
,
't'
:
true
,
'u'
:
true
,
'v'
:
true
,
'w'
:
true
,
'x'
:
true
,
'y'
:
true
,
'z'
:
true
,
'A'
:
true
,
'B'
:
true
,
'C'
:
true
,
'D'
:
true
,
'E'
:
true
,
'F'
:
true
,
'G'
:
true
,
'H'
:
true
,
'I'
:
true
,
'J'
:
true
,
'K'
:
true
,
'L'
:
true
,
'M'
:
true
,
'N'
:
true
,
'O'
:
true
,
'P'
:
true
,
'Q'
:
true
,
'R'
:
true
,
'S'
:
true
,
'T'
:
true
,
'U'
:
true
,
'V'
:
true
,
'W'
:
true
,
'X'
:
true
,
'Y'
:
true
,
'Z'
:
true
,
'!'
:
true
,
// sub-delims
'$'
:
true
,
// sub-delims
'%'
:
true
,
// pct-encoded (and used in IPv6 zones)
'&'
:
true
,
// sub-delims
'('
:
true
,
// sub-delims
')'
:
true
,
// sub-delims
'*'
:
true
,
// sub-delims
'+'
:
true
,
// sub-delims
','
:
true
,
// sub-delims
'-'
:
true
,
// unreserved
'.'
:
true
,
// unreserved
':'
:
true
,
// IPv6address + Host expression's optional port
';'
:
true
,
// sub-delims
'='
:
true
,
// sub-delims
'['
:
true
,
'\'
'
:
true
,
// sub-delims
']'
:
true
,
'_'
:
true
,
// unreserved
'~'
:
true
,
// unreserved
}
// ValidHeaderFieldValue reports whether v is a valid "field-value" according to
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2 :
//
// message-header = field-name ":" [ field-value ]
// field-value = *( field-content | LWS )
// field-content = <the OCTETs making up the field-value
// and consisting of either *TEXT or combinations
// of token, separators, and quoted-string>
//
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2.2 :
//
// TEXT = <any OCTET except CTLs,
// but including LWS>
// LWS = [CRLF] 1*( SP | HT )
// CTL = <any US-ASCII control character
// (octets 0 - 31) and DEL (127)>
//
// RFC 7230 says:
// field-value = *( field-content / obs-fold )
// obj-fold = N/A to http2, and deprecated
// field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ]
// field-vchar = VCHAR / obs-text
// obs-text = %x80-FF
// VCHAR = "any visible [USASCII] character"
//
// http2 further says: "Similarly, HTTP/2 allows header field values
// that are not valid. While most of the values that can be encoded
// will not alter header field parsing, carriage return (CR, ASCII
// 0xd), line feed (LF, ASCII 0xa), and the zero character (NUL, ASCII
// 0x0) might be exploited by an attacker if they are translated
// verbatim. Any request or response that contains a character not
// permitted in a header field value MUST be treated as malformed
// (Section 8.1.2.6). Valid characters are defined by the
// field-content ABNF rule in Section 3.2 of [RFC7230]."
//
// This function does not (yet?) properly handle the rejection of
// strings that begin or end with SP or HTAB.
func
ValidHeaderFieldValue
(
v
string
)
bool
{
for
i
:=
0
;
i
<
len
(
v
);
i
++
{
b
:=
v
[
i
]
if
isCTL
(
b
)
&&
!
isLWS
(
b
)
{
return
false
}
}
return
true
}
vendor/golang.org/x/net/trace/trace.go
View file @
e5ed62e8
...
...
@@ -93,13 +93,17 @@ var DebugUseAfterFinish = false
//
// AuthRequest may be replaced by a program to customise its authorisation requirements.
//
// The default AuthRequest function returns (true, true) iff the request comes from localhost/127.0.0.1/[::1].
// The default AuthRequest function returns (true, true) if and only if the request
// comes from localhost/127.0.0.1/[::1].
var
AuthRequest
=
func
(
req
*
http
.
Request
)
(
any
,
sensitive
bool
)
{
// RemoteAddr is commonly in the form "IP" or "IP:port".
// If it is in the form "IP:port", split off the port.
host
,
_
,
err
:=
net
.
SplitHostPort
(
req
.
RemoteAddr
)
switch
{
case
err
!=
nil
:
// Badly formed address; fail closed.
return
false
,
false
case
host
==
"localhost"
||
host
==
"127.0.0.1"
||
host
==
"::1"
:
if
err
!=
nil
{
host
=
req
.
RemoteAddr
}
switch
host
{
case
"localhost"
,
"127.0.0.1"
,
"::1"
:
return
true
,
true
default
:
return
false
,
false
...
...
vendor/golang.org/x/net/websocket/hybi.go
View file @
e5ed62e8
...
...
@@ -81,9 +81,6 @@ type hybiFrameReader struct {
func
(
frame
*
hybiFrameReader
)
Read
(
msg
[]
byte
)
(
n
int
,
err
error
)
{
n
,
err
=
frame
.
reader
.
Read
(
msg
)
if
err
!=
nil
{
return
0
,
err
}
if
frame
.
header
.
MaskingKey
!=
nil
{
for
i
:=
0
;
i
<
n
;
i
++
{
msg
[
i
]
=
msg
[
i
]
^
frame
.
header
.
MaskingKey
[
frame
.
pos
%
4
]
...
...
vendor/golang.org/x/net/websocket/websocket.go
View file @
e5ed62e8
...
...
@@ -144,6 +144,8 @@ type frameHandler interface {
}
// Conn represents a WebSocket connection.
//
// Multiple goroutines may invoke methods on a Conn simultaneously.
type
Conn
struct
{
config
*
Config
request
*
http
.
Request
...
...
@@ -207,9 +209,6 @@ func (ws *Conn) Write(msg []byte) (n int, err error) {
}
n
,
err
=
w
.
Write
(
msg
)
w
.
Close
()
if
err
!=
nil
{
return
n
,
err
}
return
n
,
err
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment