Merge branch 'v1.3'
This commit is contained in:
commit
3776e58041
9 changed files with 111 additions and 36 deletions
10
CHANGELOG.md
10
CHANGELOG.md
|
@ -1,5 +1,15 @@
|
||||||
# Change Log
|
# Change Log
|
||||||
|
|
||||||
|
## [v1.3.2](https://github.com/containous/traefik/tree/v1.3.2) (2017-06-29)
|
||||||
|
[All Commits](https://github.com/containous/traefik/compare/v1.3.1...v1.3.2)
|
||||||
|
|
||||||
|
**Bug fixes:**
|
||||||
|
- **[acme]** Add provided certificate checking before LE certificate generation with OnHostRule option ([#1772](https://github.com/containous/traefik/pull/1772) by [nmengin](https://github.com/nmengin))
|
||||||
|
- **[k8s]** Fix race on closing event channel. ([#1798](https://github.com/containous/traefik/pull/1798) by [timoreimann](https://github.com/timoreimann))
|
||||||
|
- **[marathon]** Upgrade go-marathon to dd6cbd4. ([#1800](https://github.com/containous/traefik/pull/1800) by [timoreimann](https://github.com/timoreimann))
|
||||||
|
- **[oxy,websocket]** Problem with keepalive when switching protocol failed ([#1782](https://github.com/containous/traefik/pull/1782) by [ldez](https://github.com/ldez))
|
||||||
|
- **[oxy]** Fix proxying of unannounced trailers ([#1805](https://github.com/containous/traefik/pull/1805) by [ldez](https://github.com/ldez))
|
||||||
|
|
||||||
## [v1.3.1](https://github.com/containous/traefik/tree/v1.3.1) (2017-06-16)
|
## [v1.3.1](https://github.com/containous/traefik/tree/v1.3.1) (2017-06-16)
|
||||||
[All Commits](https://github.com/containous/traefik/compare/v1.3.0...v1.3.1)
|
[All Commits](https://github.com/containous/traefik/compare/v1.3.0...v1.3.1)
|
||||||
|
|
||||||
|
|
8
glide.lock
generated
8
glide.lock
generated
|
@ -1,5 +1,5 @@
|
||||||
hash: 068db16642eb0249ce973711f4cf44206cc201214b1990e13f89e1ac3c402635
|
hash: 4e2a6a4fe84b2843ff946fe56deae17f8c7666e2e6567d8a75f4b0bdd7cb0280
|
||||||
updated: 2017-06-27T00:25:19.890844996+02:00
|
updated: 2017-06-29T16:47:14.848940186+02:00
|
||||||
imports:
|
imports:
|
||||||
- name: cloud.google.com/go
|
- name: cloud.google.com/go
|
||||||
version: 2e6a95edb1071d750f6d7db777bf66cd2997af6c
|
version: 2e6a95edb1071d750f6d7db777bf66cd2997af6c
|
||||||
|
@ -195,7 +195,7 @@ imports:
|
||||||
- name: github.com/fatih/color
|
- name: github.com/fatih/color
|
||||||
version: 9131ab34cf20d2f6d83fdc67168a5430d1c7dc23
|
version: 9131ab34cf20d2f6d83fdc67168a5430d1c7dc23
|
||||||
- name: github.com/gambol99/go-marathon
|
- name: github.com/gambol99/go-marathon
|
||||||
version: 1b9c2582c26b632fb1fb295776d7ce40b68c36f2
|
version: dd6cbd4c2d71294a19fb89158f2a00d427f174ab
|
||||||
- name: github.com/ghodss/yaml
|
- name: github.com/ghodss/yaml
|
||||||
version: 73d445a93680fa1a78ae23a5839bad48f32ba1ee
|
version: 73d445a93680fa1a78ae23a5839bad48f32ba1ee
|
||||||
- name: github.com/go-ini/ini
|
- name: github.com/go-ini/ini
|
||||||
|
@ -409,7 +409,7 @@ imports:
|
||||||
- name: github.com/vdemeester/docker-events
|
- name: github.com/vdemeester/docker-events
|
||||||
version: be74d4929ec1ad118df54349fda4b0cba60f849b
|
version: be74d4929ec1ad118df54349fda4b0cba60f849b
|
||||||
- name: github.com/vulcand/oxy
|
- name: github.com/vulcand/oxy
|
||||||
version: ad5bdb606fa9c64db267f0e43d63834908bdb05e
|
version: 7da864c1d53bd58165435bb78bbf8c01f01c8f4a
|
||||||
repo: https://github.com/containous/oxy.git
|
repo: https://github.com/containous/oxy.git
|
||||||
vcs: git
|
vcs: git
|
||||||
subpackages:
|
subpackages:
|
||||||
|
|
|
@ -9,7 +9,7 @@ import:
|
||||||
- package: github.com/cenk/backoff
|
- package: github.com/cenk/backoff
|
||||||
- package: github.com/containous/flaeg
|
- package: github.com/containous/flaeg
|
||||||
- package: github.com/vulcand/oxy
|
- package: github.com/vulcand/oxy
|
||||||
version: ad5bdb606fa9c64db267f0e43d63834908bdb05e
|
version: 7da864c1d53bd58165435bb78bbf8c01f01c8f4a
|
||||||
repo: https://github.com/containous/oxy.git
|
repo: https://github.com/containous/oxy.git
|
||||||
vcs: git
|
vcs: git
|
||||||
subpackages:
|
subpackages:
|
||||||
|
@ -96,7 +96,7 @@ import:
|
||||||
- package: k8s.io/client-go
|
- package: k8s.io/client-go
|
||||||
version: v2.0.0
|
version: v2.0.0
|
||||||
- package: github.com/gambol99/go-marathon
|
- package: github.com/gambol99/go-marathon
|
||||||
version: 1b9c2582c26b632fb1fb295776d7ce40b68c36f2
|
version: dd6cbd4c2d71294a19fb89158f2a00d427f174ab
|
||||||
- package: github.com/ArthurHlt/go-eureka-client
|
- package: github.com/ArthurHlt/go-eureka-client
|
||||||
subpackages:
|
subpackages:
|
||||||
- eureka
|
- eureka
|
||||||
|
@ -163,10 +163,10 @@ import:
|
||||||
version: 5b8f6cc26b355ba03d7611fce3844155b7baf05b
|
version: 5b8f6cc26b355ba03d7611fce3844155b7baf05b
|
||||||
- package: golang.org/x/oauth2
|
- package: golang.org/x/oauth2
|
||||||
version: 7fdf09982454086d5570c7db3e11f360194830ca
|
version: 7fdf09982454086d5570c7db3e11f360194830ca
|
||||||
- package: github.com/rancher/go-rancher-metadata
|
|
||||||
version: 95d4962a8f0420be24fb49c2cb4f5491284c62f1
|
|
||||||
subpackages:
|
subpackages:
|
||||||
- google
|
- google
|
||||||
|
- package: github.com/rancher/go-rancher-metadata
|
||||||
|
version: 95d4962a8f0420be24fb49c2cb4f5491284c62f1
|
||||||
- package: github.com/googleapis/gax-go
|
- package: github.com/googleapis/gax-go
|
||||||
version: 9af46dd5a1713e8b5cd71106287eba3cefdde50b
|
version: 9af46dd5a1713e8b5cd71106287eba3cefdde50b
|
||||||
- package: google.golang.org/grpc
|
- package: google.golang.org/grpc
|
||||||
|
|
|
@ -263,7 +263,7 @@ func (c *clientImpl) WatchAll(labelSelector string, stopCh <-chan struct{}) (<-c
|
||||||
// fireEvent checks if all controllers have synced before firing
|
// fireEvent checks if all controllers have synced before firing
|
||||||
// Used after startup or a reconnect
|
// Used after startup or a reconnect
|
||||||
func (c *clientImpl) fireEvent(event interface{}, eventCh chan interface{}) {
|
func (c *clientImpl) fireEvent(event interface{}, eventCh chan interface{}) {
|
||||||
if !c.ingController.HasSynced() || !c.svcController.HasSynced() || !c.epController.HasSynced() {
|
if !c.ingController.HasSynced() || !c.svcController.HasSynced() || !c.epController.HasSynced() || !c.secController.HasSynced() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
eventHandlerFunc(eventCh, event)
|
eventHandlerFunc(eventCh, event)
|
||||||
|
|
|
@ -116,11 +116,11 @@ func (p *Provider) Provide(configurationChan chan<- types.ConfigMessage, pool *s
|
||||||
}
|
}
|
||||||
|
|
||||||
notify := func(err error, time time.Duration) {
|
notify := func(err error, time time.Duration) {
|
||||||
log.Errorf("Provider connection error %+v, retrying in %s", err, time)
|
log.Errorf("Provider connection error: %s; retrying in %s", err, time)
|
||||||
}
|
}
|
||||||
err := backoff.RetryNotify(safe.OperationWithRecover(operation), job.NewBackOff(backoff.NewExponentialBackOff()), notify)
|
err := backoff.RetryNotify(safe.OperationWithRecover(operation), job.NewBackOff(backoff.NewExponentialBackOff()), notify)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("Cannot connect to Provider server %+v", err)
|
log.Errorf("Cannot connect to Provider: %s", err)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -180,7 +180,8 @@ func (p *Provider) loadIngresses(k8sClient Client) (*types.Configuration, error)
|
||||||
if _, exists := templateObjects.Frontends[r.Host+pa.Path]; !exists {
|
if _, exists := templateObjects.Frontends[r.Host+pa.Path]; !exists {
|
||||||
basicAuthCreds, err := handleBasicAuthConfig(i, k8sClient)
|
basicAuthCreds, err := handleBasicAuthConfig(i, k8sClient)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
log.Errorf("Failed to retrieve basic auth configuration for ingress %s/%s: %s", i.ObjectMeta.Namespace, i.ObjectMeta.Name, err)
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
templateObjects.Frontends[r.Host+pa.Path] = &types.Frontend{
|
templateObjects.Frontends[r.Host+pa.Path] = &types.Frontend{
|
||||||
Backend: r.Host + pa.Path,
|
Backend: r.Host + pa.Path,
|
||||||
|
@ -300,18 +301,15 @@ func handleBasicAuthConfig(i *v1beta1.Ingress, k8sClient Client) ([]string, erro
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
if strings.ToLower(authType) != "basic" {
|
if strings.ToLower(authType) != "basic" {
|
||||||
return nil, fmt.Errorf("unsupported auth-type: %q", authType)
|
return nil, fmt.Errorf("unsupported auth-type on annotation ingress.kubernetes.io/auth-type: %q", authType)
|
||||||
}
|
}
|
||||||
authSecret := i.Annotations[annotationKubernetesAuthSecret]
|
authSecret := i.Annotations[annotationKubernetesAuthSecret]
|
||||||
if authSecret == "" {
|
if authSecret == "" {
|
||||||
return nil, errors.New("auth-secret annotation must be set")
|
return nil, errors.New("auth-secret annotation ingress.kubernetes.io/auth-secret must be set")
|
||||||
}
|
}
|
||||||
basicAuthCreds, err := loadAuthCredentials(i.Namespace, authSecret, k8sClient)
|
basicAuthCreds, err := loadAuthCredentials(i.Namespace, authSecret, k8sClient)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, fmt.Errorf("failed to load auth credentials: %s", err)
|
||||||
}
|
|
||||||
if len(basicAuthCreds) == 0 {
|
|
||||||
return nil, errors.New("secret file without credentials")
|
|
||||||
}
|
}
|
||||||
return basicAuthCreds, nil
|
return basicAuthCreds, nil
|
||||||
}
|
}
|
||||||
|
@ -324,9 +322,9 @@ func loadAuthCredentials(namespace, secretName string, k8sClient Client) ([]stri
|
||||||
case !ok:
|
case !ok:
|
||||||
return nil, fmt.Errorf("secret %q/%q not found", namespace, secretName)
|
return nil, fmt.Errorf("secret %q/%q not found", namespace, secretName)
|
||||||
case secret == nil:
|
case secret == nil:
|
||||||
return nil, errors.New("secret data must not be nil")
|
return nil, fmt.Errorf("data for secret %q/%q must not be nil", namespace, secretName)
|
||||||
case len(secret.Data) != 1:
|
case len(secret.Data) != 1:
|
||||||
return nil, errors.New("secret must contain single element only")
|
return nil, fmt.Errorf("found %d elements for secret %q/%q, must be single element exactly", len(secret.Data), namespace, secretName)
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
var firstSecret []byte
|
var firstSecret []byte
|
||||||
|
@ -341,6 +339,10 @@ func loadAuthCredentials(namespace, secretName string, k8sClient Client) ([]stri
|
||||||
creds = append(creds, cred)
|
creds = append(creds, cred)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if len(creds) == 0 {
|
||||||
|
return nil, fmt.Errorf("secret %q/%q does not contain any credentials", namespace, secretName)
|
||||||
|
}
|
||||||
|
|
||||||
return creds, nil
|
return creds, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
5
vendor/github.com/gambol99/go-marathon/client.go
generated
vendored
5
vendor/github.com/gambol99/go-marathon/client.go
generated
vendored
|
@ -150,8 +150,6 @@ type Marathon interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// ErrInvalidResponse is thrown when marathon responds with invalid or error response
|
|
||||||
ErrInvalidResponse = errors.New("invalid response from Marathon")
|
|
||||||
// ErrMarathonDown is thrown when all the marathon endpoints are down
|
// ErrMarathonDown is thrown when all the marathon endpoints are down
|
||||||
ErrMarathonDown = errors.New("all the Marathon hosts are presently down")
|
ErrMarathonDown = errors.New("all the Marathon hosts are presently down")
|
||||||
// ErrTimeoutError is thrown when the operation has timed out
|
// ErrTimeoutError is thrown when the operation has timed out
|
||||||
|
@ -303,8 +301,7 @@ func (r *marathonClient) apiCall(method, path string, body, result interface{})
|
||||||
if response.StatusCode >= 200 && response.StatusCode <= 299 {
|
if response.StatusCode >= 200 && response.StatusCode <= 299 {
|
||||||
if result != nil {
|
if result != nil {
|
||||||
if err := json.Unmarshal(respBody, result); err != nil {
|
if err := json.Unmarshal(respBody, result); err != nil {
|
||||||
r.debugLog.Printf("apiCall(): failed to unmarshall the response from marathon, error: %s\n", err)
|
return fmt.Errorf("failed to unmarshal response from Marathon: %s", err)
|
||||||
return ErrInvalidResponse
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
2
vendor/github.com/gambol99/go-marathon/health.go
generated
vendored
2
vendor/github.com/gambol99/go-marathon/health.go
generated
vendored
|
@ -27,7 +27,7 @@ type HealthCheck struct {
|
||||||
GracePeriodSeconds int `json:"gracePeriodSeconds,omitempty"`
|
GracePeriodSeconds int `json:"gracePeriodSeconds,omitempty"`
|
||||||
IntervalSeconds int `json:"intervalSeconds,omitempty"`
|
IntervalSeconds int `json:"intervalSeconds,omitempty"`
|
||||||
TimeoutSeconds int `json:"timeoutSeconds,omitempty"`
|
TimeoutSeconds int `json:"timeoutSeconds,omitempty"`
|
||||||
IgnoreHTTP1xx *bool `json:"ignoreHttp1xx,ommitempty"`
|
IgnoreHTTP1xx *bool `json:"ignoreHttp1xx,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetCommand sets the given command on the health check.
|
// SetCommand sets the given command on the health check.
|
||||||
|
|
42
vendor/github.com/gambol99/go-marathon/unreachable_strategy.go
generated
vendored
42
vendor/github.com/gambol99/go-marathon/unreachable_strategy.go
generated
vendored
|
@ -16,12 +16,54 @@ limitations under the License.
|
||||||
|
|
||||||
package marathon
|
package marathon
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
const UnreachableStrategyAbsenceReasonDisabled = "disabled"
|
||||||
|
|
||||||
// UnreachableStrategy is the unreachable strategy applied to an application.
|
// UnreachableStrategy is the unreachable strategy applied to an application.
|
||||||
type UnreachableStrategy struct {
|
type UnreachableStrategy struct {
|
||||||
|
EnabledUnreachableStrategy
|
||||||
|
AbsenceReason string
|
||||||
|
}
|
||||||
|
|
||||||
|
// EnabledUnreachableStrategy covers parameters pertaining to present unreachable strategies.
|
||||||
|
type EnabledUnreachableStrategy struct {
|
||||||
InactiveAfterSeconds *float64 `json:"inactiveAfterSeconds,omitempty"`
|
InactiveAfterSeconds *float64 `json:"inactiveAfterSeconds,omitempty"`
|
||||||
ExpungeAfterSeconds *float64 `json:"expungeAfterSeconds,omitempty"`
|
ExpungeAfterSeconds *float64 `json:"expungeAfterSeconds,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type unreachableStrategy UnreachableStrategy
|
||||||
|
|
||||||
|
// UnmarshalJSON unmarshals the given JSON into an UnreachableStrategy. It
|
||||||
|
// populates parameters for present strategies, and otherwise only sets the
|
||||||
|
// absence reason.
|
||||||
|
func (us *UnreachableStrategy) UnmarshalJSON(b []byte) error {
|
||||||
|
var u unreachableStrategy
|
||||||
|
var errEnabledUS, errNonEnabledUS error
|
||||||
|
if errEnabledUS = json.Unmarshal(b, &u); errEnabledUS == nil {
|
||||||
|
*us = UnreachableStrategy(u)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if errNonEnabledUS = json.Unmarshal(b, &us.AbsenceReason); errNonEnabledUS == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Errorf("failed to unmarshal unreachable strategy: unmarshaling into enabled returned error '%s'; unmarshaling into non-enabled returned error '%s'", errEnabledUS, errNonEnabledUS)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON marshals the unreachable strategy.
|
||||||
|
func (us *UnreachableStrategy) MarshalJSON() ([]byte, error) {
|
||||||
|
if us.AbsenceReason == "" {
|
||||||
|
return json.Marshal(us.EnabledUnreachableStrategy)
|
||||||
|
}
|
||||||
|
|
||||||
|
return json.Marshal(us.AbsenceReason)
|
||||||
|
}
|
||||||
|
|
||||||
// SetInactiveAfterSeconds sets the period after which instance will be marked as inactive.
|
// SetInactiveAfterSeconds sets the period after which instance will be marked as inactive.
|
||||||
func (us UnreachableStrategy) SetInactiveAfterSeconds(cap float64) UnreachableStrategy {
|
func (us UnreachableStrategy) SetInactiveAfterSeconds(cap float64) UnreachableStrategy {
|
||||||
us.InactiveAfterSeconds = &cap
|
us.InactiveAfterSeconds = &cap
|
||||||
|
|
46
vendor/github.com/vulcand/oxy/forward/fwd.go
generated
vendored
46
vendor/github.com/vulcand/oxy/forward/fwd.go
generated
vendored
|
@ -159,7 +159,9 @@ func (f *Forwarder) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
// serveHTTP forwards HTTP traffic using the configured transport
|
// serveHTTP forwards HTTP traffic using the configured transport
|
||||||
func (f *httpForwarder) serveHTTP(w http.ResponseWriter, req *http.Request, ctx *handlerContext) {
|
func (f *httpForwarder) serveHTTP(w http.ResponseWriter, req *http.Request, ctx *handlerContext) {
|
||||||
start := time.Now().UTC()
|
start := time.Now().UTC()
|
||||||
|
|
||||||
response, err := f.roundTripper.RoundTrip(f.copyRequest(req, req.URL))
|
response, err := f.roundTripper.RoundTrip(f.copyRequest(req, req.URL))
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.log.Errorf("Error forwarding to %v, err: %v", req.URL, err)
|
ctx.log.Errorf("Error forwarding to %v, err: %v", req.URL, err)
|
||||||
ctx.errHandler.ServeHTTP(w, req, err)
|
ctx.errHandler.ServeHTTP(w, req, err)
|
||||||
|
@ -169,6 +171,16 @@ func (f *httpForwarder) serveHTTP(w http.ResponseWriter, req *http.Request, ctx
|
||||||
utils.CopyHeaders(w.Header(), response.Header)
|
utils.CopyHeaders(w.Header(), response.Header)
|
||||||
// Remove hop-by-hop headers.
|
// Remove hop-by-hop headers.
|
||||||
utils.RemoveHeaders(w.Header(), HopHeaders...)
|
utils.RemoveHeaders(w.Header(), HopHeaders...)
|
||||||
|
|
||||||
|
announcedTrailerKeyCount := len(response.Trailer)
|
||||||
|
if announcedTrailerKeyCount > 0 {
|
||||||
|
trailerKeys := make([]string, 0, announcedTrailerKeyCount)
|
||||||
|
for k := range response.Trailer {
|
||||||
|
trailerKeys = append(trailerKeys, k)
|
||||||
|
}
|
||||||
|
w.Header().Add("Trailer", strings.Join(trailerKeys, ", "))
|
||||||
|
}
|
||||||
|
|
||||||
w.WriteHeader(response.StatusCode)
|
w.WriteHeader(response.StatusCode)
|
||||||
|
|
||||||
stream := f.streamResponse
|
stream := f.streamResponse
|
||||||
|
@ -179,6 +191,20 @@ func (f *httpForwarder) serveHTTP(w http.ResponseWriter, req *http.Request, ctx
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
written, err := io.Copy(newResponseFlusher(w, stream), response.Body)
|
written, err := io.Copy(newResponseFlusher(w, stream), response.Body)
|
||||||
|
if err != nil {
|
||||||
|
ctx.log.Errorf("Error copying upstream response body: %v", err)
|
||||||
|
ctx.errHandler.ServeHTTP(w, req, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
defer response.Body.Close()
|
||||||
|
|
||||||
|
forceSetTrailers := len(response.Trailer) != announcedTrailerKeyCount
|
||||||
|
shallowCopyTrailers(w.Header(), response.Trailer, forceSetTrailers)
|
||||||
|
|
||||||
|
if written != 0 {
|
||||||
|
w.Header().Set(ContentLength, strconv.FormatInt(written, 10))
|
||||||
|
}
|
||||||
|
|
||||||
if req.TLS != nil {
|
if req.TLS != nil {
|
||||||
ctx.log.Infof("Round trip: %v, code: %v, duration: %v tls:version: %x, tls:resume:%t, tls:csuite:%x, tls:server:%v",
|
ctx.log.Infof("Round trip: %v, code: %v, duration: %v tls:version: %x, tls:resume:%t, tls:csuite:%x, tls:server:%v",
|
||||||
|
@ -192,17 +218,6 @@ func (f *httpForwarder) serveHTTP(w http.ResponseWriter, req *http.Request, ctx
|
||||||
req.URL, response.StatusCode, time.Now().UTC().Sub(start))
|
req.URL, response.StatusCode, time.Now().UTC().Sub(start))
|
||||||
}
|
}
|
||||||
|
|
||||||
defer response.Body.Close()
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
ctx.log.Errorf("Error copying upstream response Body: %v", err)
|
|
||||||
ctx.errHandler.ServeHTTP(w, req, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if written != 0 {
|
|
||||||
w.Header().Set(ContentLength, strconv.FormatInt(written, 10))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// copyRequest makes a copy of the specified request to be sent using the configured
|
// copyRequest makes a copy of the specified request to be sent using the configured
|
||||||
|
@ -364,3 +379,12 @@ func isWebsocketRequest(req *http.Request) bool {
|
||||||
}
|
}
|
||||||
return containsHeader(Connection, "upgrade") && containsHeader(Upgrade, "websocket")
|
return containsHeader(Connection, "upgrade") && containsHeader(Upgrade, "websocket")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func shallowCopyTrailers(dstHeader, srcTrailer http.Header, forceSetTrailers bool) {
|
||||||
|
for k, vv := range srcTrailer {
|
||||||
|
if forceSetTrailers {
|
||||||
|
k = http.TrailerPrefix + k
|
||||||
|
}
|
||||||
|
dstHeader[k] = vv
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue