mirror of
https://github.com/alibaba/higress.git
synced 2026-03-03 16:10:48 +08:00
153 lines
3.7 KiB
Go
153 lines
3.7 KiB
Go
// Copyright (c) 2022 Alibaba Group Holding Ltd.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package annotations
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
"net/url"
|
|
"strings"
|
|
|
|
networking "istio.io/api/networking/v1alpha3"
|
|
)
|
|
|
|
const (
|
|
appRoot = "app-root"
|
|
temporalRedirect = "temporal-redirect"
|
|
permanentRedirect = "permanent-redirect"
|
|
permanentRedirectCode = "permanent-redirect-code"
|
|
sslRedirect = "ssl-redirect"
|
|
forceSSLRedirect = "force-ssl-redirect"
|
|
|
|
defaultPermanentRedirectCode = 301
|
|
defaultTemporalRedirectCode = 302
|
|
)
|
|
|
|
var (
|
|
_ Parser = &redirect{}
|
|
_ RouteHandler = &redirect{}
|
|
)
|
|
|
|
type RedirectConfig struct {
|
|
AppRoot string
|
|
|
|
URL string
|
|
|
|
Code int
|
|
|
|
httpsRedirect bool
|
|
}
|
|
|
|
type redirect struct{}
|
|
|
|
func (r redirect) Parse(annotations Annotations, config *Ingress, _ *GlobalContext) error {
|
|
if !needRedirectConfig(annotations) {
|
|
return nil
|
|
}
|
|
|
|
redirectConfig := &RedirectConfig{
|
|
Code: defaultPermanentRedirectCode,
|
|
}
|
|
config.Redirect = redirectConfig
|
|
|
|
redirectConfig.AppRoot, _ = annotations.ParseStringASAP(appRoot)
|
|
|
|
httpsRedirect, _ := annotations.ParseBoolASAP(sslRedirect)
|
|
forceHTTPSRedirect, _ := annotations.ParseBoolASAP(forceSSLRedirect)
|
|
if httpsRedirect || forceHTTPSRedirect {
|
|
redirectConfig.httpsRedirect = true
|
|
}
|
|
|
|
// temporal redirect is firstly applied.
|
|
tr, err := annotations.ParseStringASAP(temporalRedirect)
|
|
if err != nil && !IsMissingAnnotations(err) {
|
|
return nil
|
|
}
|
|
if tr != "" && isValidURL(tr) == nil {
|
|
redirectConfig.URL = tr
|
|
redirectConfig.Code = defaultTemporalRedirectCode
|
|
return nil
|
|
}
|
|
|
|
// permanent redirect
|
|
// url
|
|
pr, err := annotations.ParseStringASAP(permanentRedirect)
|
|
if err != nil && !IsMissingAnnotations(err) {
|
|
return nil
|
|
}
|
|
if pr != "" && isValidURL(pr) == nil {
|
|
redirectConfig.URL = pr
|
|
}
|
|
// code
|
|
if prc, err := annotations.ParseIntASAP(permanentRedirectCode); err == nil {
|
|
if prc < http.StatusMultipleChoices || prc > http.StatusPermanentRedirect {
|
|
prc = defaultPermanentRedirectCode
|
|
}
|
|
redirectConfig.Code = prc
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (r redirect) ApplyRoute(route *networking.HTTPRoute, config *Ingress) {
|
|
redirectConfig := config.Redirect
|
|
if redirectConfig == nil {
|
|
return
|
|
}
|
|
|
|
var redirectPolicy *networking.HTTPRedirect
|
|
if redirectConfig.URL != "" {
|
|
parseURL, err := url.Parse(redirectConfig.URL)
|
|
if err != nil {
|
|
return
|
|
}
|
|
redirectPolicy = &networking.HTTPRedirect{
|
|
Scheme: parseURL.Scheme,
|
|
Authority: parseURL.Host,
|
|
Uri: parseURL.Path,
|
|
RedirectCode: uint32(redirectConfig.Code),
|
|
}
|
|
} else if redirectConfig.httpsRedirect {
|
|
redirectPolicy = &networking.HTTPRedirect{
|
|
Scheme: "https",
|
|
// 308 is the default code for ssl redirect
|
|
RedirectCode: 308,
|
|
}
|
|
}
|
|
|
|
route.Redirect = redirectPolicy
|
|
}
|
|
|
|
func needRedirectConfig(annotations Annotations) bool {
|
|
return annotations.HasASAP(temporalRedirect) ||
|
|
annotations.HasASAP(permanentRedirect) ||
|
|
annotations.HasASAP(sslRedirect) ||
|
|
annotations.HasASAP(forceSSLRedirect) ||
|
|
annotations.HasASAP(appRoot)
|
|
}
|
|
|
|
func isValidURL(s string) error {
|
|
u, err := url.Parse(s)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if !strings.HasPrefix(u.Scheme, "http") {
|
|
return fmt.Errorf("only http and https are valid protocols (%v)", u.Scheme)
|
|
}
|
|
|
|
return nil
|
|
}
|