Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HTTP2 support in router #2953

Merged
merged 42 commits into from
Jul 11, 2022
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
e1357bc
initial commit
Amila-Rukshan May 24, 2022
869abce
Merge branch 'wso2:main' into http2-support
Amila-Rukshan May 24, 2022
4c89336
enable upsteam http2
Amila-Rukshan May 25, 2022
86e8f5f
Merge branch 'wso2:main' into http2-support
Amila-Rukshan May 26, 2022
76f70f4
checked http2 configs
Amila-Rukshan May 27, 2022
5bbb5a1
Merge branch 'http2-support' of https://github.com/Amila-Rukshan/prod…
Amila-Rukshan May 27, 2022
1399843
commented new code
Amila-Rukshan May 27, 2022
2a9ec20
http2 server clear text and tls with tests
Amila-Rukshan Jun 2, 2022
bb6ec7e
Merge branch 'wso2:main' into http2-support
Amila-Rukshan Jun 2, 2022
5a1fbf8
Merge branch 'http2-support' of https://github.com/Amila-Rukshan/prod…
Amila-Rukshan Jun 2, 2022
0cf9ad9
new lines added at the end of files duplicate test class names corrected
Amila-Rukshan Jun 3, 2022
0110d42
http2 codec config in router added and formatting
Amila-Rukshan Jun 4, 2022
ab154e8
http2 client and tests added
Amila-Rukshan Jun 4, 2022
de1ce94
failing test case fixed
Amila-Rukshan Jun 6, 2022
ae1384a
default http2 options added for assuming untrusted upstreams
Amila-Rukshan Jun 6, 2022
42390c2
address review comments
Amila-Rukshan Jun 7, 2022
b802f7d
alpn protocols limited use when only http2 enabled
Amila-Rukshan Jun 7, 2022
cae2be6
Merge branch 'wso2:main' into http2-support
Amila-Rukshan Jun 7, 2022
f9eda01
extension name changed
Amila-Rukshan Jun 8, 2022
9e793f4
Merge branch 'http2-support' of https://github.com/Amila-Rukshan/prod…
Amila-Rukshan Jun 8, 2022
9dbf293
apim secured api test case added
Amila-Rukshan Jun 8, 2022
53af4f1
test cases updated
Amila-Rukshan Jun 8, 2022
128e498
Merge branch 'wso2:main' into http2-support
Amila-Rukshan Jun 8, 2022
94f9c5e
only http1 or http2 options added to fix runtime failures
Amila-Rukshan Jun 9, 2022
23ce80e
use HttpProtocolOptions_ExplicitHttpConfig added to avoid deprecated …
Amila-Rukshan Jun 9, 2022
9a21ea3
Merge branch 'wso2:main' into http2-support
Amila-Rukshan Jun 9, 2022
901c00f
http2 options defaults added
Amila-Rukshan Jun 9, 2022
bcfe975
license year fixed
Amila-Rukshan Jun 9, 2022
e5ffee1
Merge branch 'wso2:main' into http2-support
Amila-Rukshan Jun 20, 2022
ea24a78
Merge branch 'wso2:main' into http2-support
Amila-Rukshan Jun 29, 2022
a004d16
fomatting issue fixed
Amila-Rukshan Jun 29, 2022
37b2fed
fomatting issue
Amila-Rukshan Jun 29, 2022
d75e08d
new line added
Amila-Rukshan Jun 29, 2022
92e2078
Merge branch 'wso2:main' into http2-support
Amila-Rukshan Jun 29, 2022
7551619
k8s config-toml upadated with http2 options
Amila-Rukshan Jun 29, 2022
8505d01
Merge branch 'http2-support' of https://github.com/Amila-Rukshan/prod…
Amila-Rukshan Jun 29, 2022
225c23f
Merge branch 'wso2:main' into http2-support
Amila-Rukshan Jun 29, 2022
8ac01d3
removed default http2 upstream configs from config.toml
Amila-Rukshan Jul 5, 2022
23b8a51
remove unwanted types for hashmap
Amila-Rukshan Jul 5, 2022
3d05bef
removed http2 default configs from k8s config map
Amila-Rukshan Jul 5, 2022
5aed0d7
Merge branch 'main' into http2-support
Amila-Rukshan Jul 6, 2022
57d07c5
Merge branch 'main' into http2-support
Amila-Rukshan Jul 11, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions adapter/config/default_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ var defaultConfig = &Config{
ListenerPort: 9090,
SecuredListenerHost: "0.0.0.0",
SecuredListenerPort: 9095,
ListenerCodecType: "AUTO",
ClusterTimeoutInSeconds: 20,
EnforcerResponseTimeoutInSeconds: 20,
KeyStore: keystore{
Expand Down Expand Up @@ -118,6 +119,10 @@ var defaultConfig = &Config{
DNSRefreshRate: 5000,
RespectDNSTtl: false,
},
HTTP2: upstreamHTTP2Options{
InitialConnectionWindowSize: 1048576.0,
InitialStreamWindowSize: 65536.0,
},
},
Connection: connection{
Timeouts: connectionTimeouts{
Expand Down
7 changes: 7 additions & 0 deletions adapter/config/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ type envoy struct {
ListenerPort uint32
SecuredListenerHost string
SecuredListenerPort uint32
ListenerCodecType string
ClusterTimeoutInSeconds time.Duration
EnforcerResponseTimeoutInSeconds time.Duration `default:"20"`
KeyStore keystore
Expand Down Expand Up @@ -223,6 +224,7 @@ type envoyUpstream struct {
Health upstreamHealth
DNS upstreamDNS
Retry upstreamRetry
HTTP2 upstreamHTTP2Options
}

type upstreamTLS struct {
Expand Down Expand Up @@ -252,6 +254,11 @@ type upstreamDNS struct {
RespectDNSTtl bool
}

type upstreamHTTP2Options struct {
InitialConnectionWindowSize uint32
InitialStreamWindowSize uint32
}

type upstreamRetry struct {
MaxRetryCount uint32
BaseIntervalInMillis uint32
Expand Down
1 change: 1 addition & 0 deletions adapter/internal/oasparser/constants/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ const (
XWso2BasePath string = "x-wso2-basePath"
XWso2Label string = "x-wso2-label"
XWso2Cors string = "x-wso2-cors"
XWso2HTTP2Enabled string = "x-wso2-http2-enabled"
Amila-Rukshan marked this conversation as resolved.
Show resolved Hide resolved
XThrottlingTier string = "x-throttling-tier"
XWso2ThrottlingTier string = "x-wso2-throttling-tier"
XAuthHeader string = "x-wso2-auth-header"
Expand Down
17 changes: 16 additions & 1 deletion adapter/internal/oasparser/envoyconf/listener.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ func createListeners(conf *config.Config) []*listenerv3.Listener {
var listeners []*listenerv3.Listener

manager := &hcmv3.HttpConnectionManager{
CodecType: hcmv3.HttpConnectionManager_AUTO,
CodecType: getListenerCodecType(conf.Envoy.ListenerCodecType),
StatPrefix: httpConManagerStartPrefix,
// WebSocket upgrades enabled from the HCM
UpgradeConfigs: []*hcmv3.HttpConnectionManager_UpgradeConfig{{
Expand Down Expand Up @@ -317,3 +317,18 @@ func getTracing(conf *config.Config) (*hcmv3.HttpConnectionManager_Tracing, erro

return tracing, nil
}

func getListenerCodecType(codecType string) hcmv3.HttpConnectionManager_CodecType {
switch codecType {
case "AUTO":
return hcmv3.HttpConnectionManager_AUTO
case "HTTP1":
return hcmv3.HttpConnectionManager_HTTP1
case "HTTP2":
return hcmv3.HttpConnectionManager_HTTP2
case "HTTP3":
Amila-Rukshan marked this conversation as resolved.
Show resolved Hide resolved
return hcmv3.HttpConnectionManager_HTTP3
default:
return hcmv3.HttpConnectionManager_AUTO
}
}
16 changes: 16 additions & 0 deletions adapter/internal/oasparser/envoyconf/routes_with_clusters.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import (
extAuthService "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/ext_authz/v3"
lua "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/lua/v3"
tlsv3 "github.com/envoyproxy/go-control-plane/envoy/extensions/transport_sockets/tls/v3"

envoy_type_matcherv3 "github.com/envoyproxy/go-control-plane/envoy/type/matcher/v3"
"github.com/envoyproxy/go-control-plane/pkg/wellknown"

Expand Down Expand Up @@ -92,6 +93,7 @@ func CreateRoutesWithClusters(mgwSwagger model.MgwSwagger, upstreamCerts map[str
// check API level production endpoints available
if mgwSwagger.GetProdEndpoints() != nil && len(mgwSwagger.GetProdEndpoints().Endpoints) > 0 {
apiLevelEndpointProd := mgwSwagger.GetProdEndpoints()
apiLevelEndpointProd.HTTP2Enabled = mgwSwagger.GetXWso2HTTP2Enabled()
apiLevelbasePath = strings.TrimSuffix(apiLevelEndpointProd.Endpoints[0].Basepath, "/")
apiLevelClusterNameProd = getClusterName(apiLevelEndpointProd.EndpointPrefix, organizationID, vHost, apiTitle,
apiVersion, "")
Expand All @@ -116,6 +118,7 @@ func CreateRoutesWithClusters(mgwSwagger model.MgwSwagger, upstreamCerts map[str
// check API level sandbox endpoints available
if mgwSwagger.GetSandEndpoints() != nil && len(mgwSwagger.GetSandEndpoints().Endpoints) > 0 {
apiLevelEndpointSand := mgwSwagger.GetSandEndpoints()
apiLevelEndpointSand.HTTP2Enabled = mgwSwagger.GetXWso2HTTP2Enabled()
if apiLevelbasePath == "" {
apiLevelbasePath = strings.TrimSuffix(apiLevelEndpointSand.Endpoints[0].Basepath, "/")
}
Expand Down Expand Up @@ -559,6 +562,18 @@ func processEndpoints(clusterName string, clusterDetails *model.EndpointCluster,
}
}

// Enable http2 protocol for the cluster
if clusterDetails.HTTP2Enabled {
cluster.Http2ProtocolOptions = &corev3.Http2ProtocolOptions{
InitialConnectionWindowSize: &wrapperspb.UInt32Value{
Value: conf.Envoy.Upstream.HTTP2.InitialConnectionWindowSize,
},
InitialStreamWindowSize: &wrapperspb.UInt32Value{
Value: conf.Envoy.Upstream.HTTP2.InitialStreamWindowSize,
},
}
}

// service discovery itself will be handling loadbancing etc.
// Therefore mutiple endpoint support is not needed, hence consider only.
serviceDiscoveryString := clusterDetails.Endpoints[0].ServiceDiscoveryString
Expand Down Expand Up @@ -608,6 +623,7 @@ func createUpstreamTLSContext(upstreamCerts []byte, address *corev3.Address) *tl
CipherSuites: ciphersArray,
},
TlsCertificates: []*tlsv3.TlsCertificate{tlsCert},
// AlpnProtocols: []string{"h2", "http/1.1"},
Amila-Rukshan marked this conversation as resolved.
Show resolved Hide resolved
Amila-Rukshan marked this conversation as resolved.
Show resolved Hide resolved
},
}

Expand Down
12 changes: 12 additions & 0 deletions adapter/internal/oasparser/model/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,18 @@ func getXWso2Basepath(vendorExtensions map[string]interface{}) string {
return xWso2basepath
}

// getXWso2HTTP2Enabled extracts the value of XWso2HTTP2Enabled extension.
// if the property is not available, false is returned.
func getXWso2HTTP2Enabled(vendorExtensions map[string]interface{}) bool {
xWso2HTTP2Enabled := false
if y, found := vendorExtensions[constants.XWso2HTTP2Enabled]; found {
if val, ok := y.(bool); ok {
xWso2HTTP2Enabled = val
}
}
return xWso2HTTP2Enabled
}

// ResolveThrottlingTier extracts the value of x-wso2-throttling-tier and
// x-throttling-tier extension. if x-wso2-throttling-tier is available it
// will be prioritized.
Expand Down
14 changes: 14 additions & 0 deletions adapter/internal/oasparser/model/mgw_swagger.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ type MgwSwagger struct {
xWso2Endpoints map[string]*EndpointCluster
resources []*Resource
xWso2Basepath string
xWso2HTTP2Enabled bool
xWso2Cors *CorsConfig
securityScheme []SecurityScheme
security []map[string][]string
Expand All @@ -80,6 +81,8 @@ type EndpointCluster struct {
EndpointType string
Config *EndpointConfig
SecurityConfig EndpointSecurity
// Is http2 protocol enabled
HTTP2Enabled bool
}

// Endpoint represents the structure of an endpoint.
Expand Down Expand Up @@ -185,6 +188,11 @@ func (swagger *MgwSwagger) GetXWso2Basepath() string {
return swagger.xWso2Basepath
}

// GetXWso2HTTP2Enabled returns the http2enabled set via the vendor extension.
func (swagger *MgwSwagger) GetXWso2HTTP2Enabled() bool {
return swagger.xWso2HTTP2Enabled
}

// GetVendorExtensions returns the map of vendor extensions which are defined
// at openAPI's root level.
func (swagger *MgwSwagger) GetVendorExtensions() map[string]interface{} {
Expand Down Expand Up @@ -424,6 +432,7 @@ func (swagger *MgwSwagger) SetXWso2Extensions() error {
swagger.setXWso2ThrottlingTier()
swagger.setDisableSecurity()
swagger.setXWso2AuthHeader()
swagger.setXWso2HTTP2Enabled()

// Error nil for successful execution
return nil
Expand Down Expand Up @@ -896,6 +905,11 @@ func (swagger *MgwSwagger) setXWso2Basepath() {
}
}

func (swagger *MgwSwagger) setXWso2HTTP2Enabled() {
extHTTP2Enabled := getXWso2HTTP2Enabled(swagger.vendorExtensions)
swagger.xWso2HTTP2Enabled = extHTTP2Enabled
}

func (swagger *MgwSwagger) setXWso2Cors() {
if cors, corsFound := swagger.vendorExtensions[constants.XWso2Cors]; corsFound {
logger.LoggerOasparser.Debugf("%v configuration is available", constants.XWso2Cors)
Expand Down
4 changes: 4 additions & 0 deletions integration/mock-backend-server/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@
<groupId>io.netty</groupId>
<artifactId>netty-codec-http</artifactId>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-codec-http2</artifactId>
</dependency>
<dependency>
<groupId>org.json.wso2</groupId>
<artifactId>json</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,7 @@ public class Constants {
public static final int INTERCEPTOR_STATUS_SERVER_PORT = 2370;
public static final int MTLS_INTERCEPTOR_HANDLER_SERVER_PORT = 2371;
public static final int WEBSOCKET_SERVER_PORT = 2360;

public static final int MOCK_BACKEND_HTTP2_SERVER_CLEAR_TEXT_PORT = 2350;
public static final int MOCK_BACKEND_HTTP2_SERVER_SECURED_PORT = 2351;
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
package org.wso2.choreo.connect.mockbackend;

import org.wso2.choreo.connect.mockbackend.async.MockAsyncServer;
import org.wso2.choreo.connect.mockbackend.http2.Http2MockBackend;

import java.util.Arrays;
import java.util.List;
Expand Down Expand Up @@ -55,5 +56,17 @@ public static void main(String[] args) {
MockAsyncServer mockAsyncServer = new MockAsyncServer(Constants.WEBSOCKET_SERVER_PORT);
mockAsyncServer.start();
}

if(argList.contains("-http2-server-enabled")){
// clear text server
Http2MockBackend http2BackendProdClearText = new Http2MockBackend(Constants.MOCK_BACKEND_HTTP2_SERVER_CLEAR_TEXT_PORT, false, false);
http2BackendProdClearText.startServer();
}

if(argList.contains("-http2-tls-server-enabled")){
// secured server
Http2MockBackend http2BackendProdTLS = new Http2MockBackend(Constants.MOCK_BACKEND_HTTP2_SERVER_SECURED_PORT, true, false);
http2BackendProdTLS.startServer();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
* Copyright (c) 2022, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you 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 org.wso2.choreo.connect.mockbackend.http2;

import io.netty.buffer.EmptyByteBuf;
import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http2.DefaultHttp2DataFrame;
import io.netty.handler.codec.http2.DefaultHttp2Headers;
import io.netty.handler.codec.http2.DefaultHttp2HeadersFrame;
import io.netty.handler.codec.http2.DefaultHttp2WindowUpdateFrame;
import io.netty.handler.codec.http2.Http2DataFrame;
import io.netty.handler.codec.http2.Http2FrameStream;
import io.netty.handler.codec.http2.Http2Headers;
import io.netty.handler.codec.http2.Http2HeadersFrame;

import static io.netty.handler.codec.http.HttpResponseStatus.OK;

/**
* Handler implementation for the http/2 echo server without content
* aggregation. This echo backs the header/data
* frames as soon as they arrive without any content aggregation against stream
* id.
*/
public class EchoHttp2ServerHandler extends ChannelDuplexHandler {
Amila-Rukshan marked this conversation as resolved.
Show resolved Hide resolved

@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
if (msg instanceof Http2HeadersFrame) {
onHeadersRead(ctx, (Http2HeadersFrame) msg);
} else if (msg instanceof Http2DataFrame) {
onDataRead(ctx, (Http2DataFrame) msg);
} else {
super.channelRead(ctx, msg);
}
}

@Override
public void channelReadComplete(ChannelHandlerContext ctx) {
ctx.flush();
}

private static void onDataRead(ChannelHandlerContext ctx, Http2DataFrame data) {
Http2FrameStream stream = data.stream();
ctx.write(new DefaultHttp2DataFrame(data.content(), data.isEndStream()).stream(stream));
// Update the flow-controller
ctx.write(new DefaultHttp2WindowUpdateFrame(data.initialFlowControlledBytes()).stream(stream));
}

private static void onHeadersRead(ChannelHandlerContext ctx, Http2HeadersFrame headersFrame) {
Http2FrameStream stream = headersFrame.stream();
Http2Headers headers = new DefaultHttp2Headers().status(OK.codeAsText());
ctx.write(new DefaultHttp2HeadersFrame(headers).stream(stream));
if (headersFrame.isEndStream()) {
ctx.write(new DefaultHttp2DataFrame(new EmptyByteBuf(ctx.alloc()), true).stream(stream));
}
}

@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
super.exceptionCaught(ctx, cause);
ctx.close();
}
}
Loading