Skip to content

Commit

Permalink
codegen: Add fix to prevent HTTP/2 event stream request hang on error (
Browse files Browse the repository at this point in the history
…#4288)

Adds fix addressing an issue where SDK's bi-directional eventstream API
operation request could hang when the HTTP/2 stream was closed by the
service with a non-200 status code.

Go 1.15 through 1.17 have an issue where the HTTP/2 request can hang
while waiting for the HTTP response, and input payload reader. The
Expect: 100-Continue workaround forces the HTTP client to wait for a
`100 continue` or other HTTP status code before attempting to wait for
the request's body to be read. This workaround is not needed for Go
1.18, as a fix to the HTTP client resolves this issue.

Related to aws/aws-sdk-go-v2#1515
  • Loading branch information
jasdel committed Feb 22, 2022
1 parent bc10f38 commit aef7eaf
Show file tree
Hide file tree
Showing 7 changed files with 78 additions and 0 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG_PENDING.md
Expand Up @@ -3,3 +3,6 @@
### SDK Enhancements

### SDK Bugs
* `service/lexruntimev2`: Add fix to prevent HTTP/2 event stream request hang on error with Go 1.15 through 1.17.
* `service/transcribestreamingservice`: Add fix to prevent HTTP/2 event stream request hang on error with Go 1.15 through 1.17.
* Adds fix addressing an issue where SDK's bi-directional eventstream API operation request could hang when the HTTP/2 stream was closed by the service with a non-200 status code.
1 change: 1 addition & 0 deletions private/model/api/operation.go
Expand Up @@ -263,6 +263,7 @@ func (c *{{ .API.StructName }}) {{ .ExportedName }}Request(` +
"X-Amz-Content-Sha256": "STREAMING-AWS4-HMAC-SHA256-EVENTS",
}))
req.Handlers.Build.Swap({{ .API.ProtocolPackage }}.BuildHandler.Name, rest.BuildHandler)
eventstreamapi.ApplyHTTPTransportFixes(req)
req.Handlers.Send.Swap(client.LogHTTPRequestHandler.Name, client.LogHTTPRequestHeaderHandler)
req.Handlers.Unmarshal.PushBack(es.runInputStream)
Expand Down
10 changes: 10 additions & 0 deletions private/protocol/eventstream/eventstreamapi/transport.go
@@ -0,0 +1,10 @@
//go:build go1.18
// +build go1.18

package eventstreamapi

import "github.com/aws/aws-sdk-go/aws/request"

// This is a no-op for Go 1.18 and above.
func ApplyHTTPTransportFixes(r *request.Request) {
}
19 changes: 19 additions & 0 deletions private/protocol/eventstream/eventstreamapi/transport_go1.17.go
@@ -0,0 +1,19 @@
//go:build !go1.18
// +build !go1.18

package eventstreamapi

import "github.com/aws/aws-sdk-go/aws/request"

// ApplyHTTPTransportFixes applies fixes to the HTTP request for proper event
// stream functionality. Go 1.15 through 1.17 HTTP client could hang forever
// when an HTTP/2 connection failed with an non-200 status code and err. Using
// Expect 100-Continue, allows the HTTP client to gracefully handle the non-200
// status code, and close the connection.
//
// This is a no-op for Go 1.18 and above.
func ApplyHTTPTransportFixes(r *request.Request) {
r.Handlers.Sign.PushBack(func(r *request.Request) {
r.HTTPRequest.Header.Set("Expect", "100-Continue")
})
}
1 change: 1 addition & 0 deletions service/lexruntimev2/api.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

42 changes: 42 additions & 0 deletions service/lexruntimev2/cust_integ_eventstream_test.go
@@ -0,0 +1,42 @@
//go:build integration
// +build integration

package lexruntimev2

import (
"testing"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/awstesting/integration"
)

func TestInteg_StartConversation_errorCase(t *testing.T) {
sess := integration.SessionWithDefaultRegion("us-west-2")

client := New(sess, &aws.Config{
Logger: t,
LogLevel: aws.LogLevel(aws.LogDebugWithEventStreamBody | aws.LogDebugWithHTTPBody),
})

_, err := client.StartConversation(&StartConversationInput{
BotAliasId: aws.String("mockAlias"),
BotId: aws.String("mockId01234567890"),
LocaleId: aws.String("mockLocale"),
SessionId: aws.String("mockSession"),
})
if err == nil {
t.Fatalf("expect error, got none")
}

aErr, ok := err.(awserr.RequestFailure)
if !ok {
t.Fatalf("expect %T error, got %T, %v", aErr, err, err)
}
if aErr.Code() == "" {
t.Errorf("expect error code, got none")
}
if aErr.Message() == "" {
t.Errorf("expect error message, got none")
}
}
2 changes: 2 additions & 0 deletions service/transcribestreamingservice/api.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit aef7eaf

Please sign in to comment.