protocol_test.go 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. package protocol_test
  2. import (
  3. "net/http"
  4. "net/url"
  5. "testing"
  6. "github.com/aws/aws-sdk-go/aws/client/metadata"
  7. "github.com/aws/aws-sdk-go/aws/request"
  8. "github.com/aws/aws-sdk-go/awstesting"
  9. "github.com/aws/aws-sdk-go/private/protocol"
  10. "github.com/aws/aws-sdk-go/private/protocol/ec2query"
  11. "github.com/aws/aws-sdk-go/private/protocol/jsonrpc"
  12. "github.com/aws/aws-sdk-go/private/protocol/query"
  13. "github.com/aws/aws-sdk-go/private/protocol/rest"
  14. "github.com/aws/aws-sdk-go/private/protocol/restjson"
  15. "github.com/aws/aws-sdk-go/private/protocol/restxml"
  16. )
  17. func xmlData(set bool, b []byte, size, delta int) {
  18. const openingTags = "<B><A>"
  19. const closingTags = "</A></B>"
  20. if !set {
  21. copy(b, []byte(openingTags))
  22. }
  23. if size == 0 {
  24. copy(b[delta-len(closingTags):], []byte(closingTags))
  25. }
  26. }
  27. func jsonData(set bool, b []byte, size, delta int) {
  28. if !set {
  29. copy(b, []byte("{\"A\": \""))
  30. }
  31. if size == 0 {
  32. copy(b[delta-len("\"}"):], []byte("\"}"))
  33. }
  34. }
  35. func buildNewRequest(data interface{}) *request.Request {
  36. v := url.Values{}
  37. v.Set("test", "TEST")
  38. v.Add("test1", "TEST1")
  39. req := &request.Request{
  40. HTTPRequest: &http.Request{
  41. Header: make(http.Header),
  42. Body: &awstesting.ReadCloser{Size: 2048},
  43. URL: &url.URL{
  44. RawQuery: v.Encode(),
  45. },
  46. },
  47. Params: &struct {
  48. LocationName string `locationName:"test"`
  49. }{
  50. "Test",
  51. },
  52. ClientInfo: metadata.ClientInfo{
  53. ServiceName: "test",
  54. TargetPrefix: "test",
  55. JSONVersion: "test",
  56. APIVersion: "test",
  57. Endpoint: "test",
  58. SigningName: "test",
  59. SigningRegion: "test",
  60. },
  61. Operation: &request.Operation{
  62. Name: "test",
  63. },
  64. }
  65. req.HTTPResponse = &http.Response{
  66. Body: &awstesting.ReadCloser{Size: 2048},
  67. Header: http.Header{
  68. "X-Amzn-Requestid": []string{"1"},
  69. },
  70. StatusCode: http.StatusOK,
  71. }
  72. if data == nil {
  73. data = &struct {
  74. _ struct{} `type:"structure"`
  75. LocationName *string `locationName:"testName"`
  76. Location *string `location:"statusCode"`
  77. A *string `type:"string"`
  78. }{}
  79. }
  80. req.Data = data
  81. return req
  82. }
  83. type expected struct {
  84. dataType int
  85. closed bool
  86. size int
  87. errExists bool
  88. }
  89. const (
  90. jsonType = iota
  91. xmlType
  92. )
  93. func checkForLeak(data interface{}, build, fn func(*request.Request), t *testing.T, result expected) {
  94. req := buildNewRequest(data)
  95. reader := req.HTTPResponse.Body.(*awstesting.ReadCloser)
  96. switch result.dataType {
  97. case jsonType:
  98. reader.FillData = jsonData
  99. case xmlType:
  100. reader.FillData = xmlData
  101. }
  102. build(req)
  103. fn(req)
  104. if result.errExists {
  105. if err := req.Error; err == nil {
  106. t.Errorf("expect error")
  107. }
  108. } else {
  109. if err := req.Error; err != nil {
  110. t.Errorf("expect nil, %v", err)
  111. }
  112. }
  113. if e, a := reader.Closed, result.closed; e != a {
  114. t.Errorf("expect %v, got %v", e, a)
  115. }
  116. if e, a := reader.Size, result.size; e != a {
  117. t.Errorf("expect %v, got %v", e, a)
  118. }
  119. }
  120. func TestJSONRpc(t *testing.T) {
  121. checkForLeak(nil, jsonrpc.Build, jsonrpc.Unmarshal, t, expected{jsonType, true, 0, false})
  122. checkForLeak(nil, jsonrpc.Build, jsonrpc.UnmarshalMeta, t, expected{jsonType, false, 2048, false})
  123. checkForLeak(nil, jsonrpc.Build, jsonrpc.UnmarshalError, t, expected{jsonType, true, 0, true})
  124. }
  125. func TestQuery(t *testing.T) {
  126. checkForLeak(nil, query.Build, query.Unmarshal, t, expected{jsonType, true, 0, false})
  127. checkForLeak(nil, query.Build, query.UnmarshalMeta, t, expected{jsonType, false, 2048, false})
  128. checkForLeak(nil, query.Build, query.UnmarshalError, t, expected{jsonType, true, 0, true})
  129. }
  130. func TestRest(t *testing.T) {
  131. // case 1: Payload io.ReadSeeker
  132. checkForLeak(nil, rest.Build, rest.Unmarshal, t, expected{jsonType, false, 2048, false})
  133. checkForLeak(nil, query.Build, query.UnmarshalMeta, t, expected{jsonType, false, 2048, false})
  134. // case 2: Payload *string
  135. // should close the body
  136. dataStr := struct {
  137. _ struct{} `type:"structure" payload:"Payload"`
  138. LocationName *string `locationName:"testName"`
  139. Location *string `location:"statusCode"`
  140. A *string `type:"string"`
  141. Payload *string `locationName:"payload" type:"blob" required:"true"`
  142. }{}
  143. checkForLeak(&dataStr, rest.Build, rest.Unmarshal, t, expected{jsonType, true, 0, false})
  144. checkForLeak(&dataStr, query.Build, query.UnmarshalMeta, t, expected{jsonType, false, 2048, false})
  145. // case 3: Payload []byte
  146. // should close the body
  147. dataBytes := struct {
  148. _ struct{} `type:"structure" payload:"Payload"`
  149. LocationName *string `locationName:"testName"`
  150. Location *string `location:"statusCode"`
  151. A *string `type:"string"`
  152. Payload []byte `locationName:"payload" type:"blob" required:"true"`
  153. }{}
  154. checkForLeak(&dataBytes, rest.Build, rest.Unmarshal, t, expected{jsonType, true, 0, false})
  155. checkForLeak(&dataBytes, query.Build, query.UnmarshalMeta, t, expected{jsonType, false, 2048, false})
  156. // case 4: Payload unsupported type
  157. // should close the body
  158. dataUnsupported := struct {
  159. _ struct{} `type:"structure" payload:"Payload"`
  160. LocationName *string `locationName:"testName"`
  161. Location *string `location:"statusCode"`
  162. A *string `type:"string"`
  163. Payload string `locationName:"payload" type:"blob" required:"true"`
  164. }{}
  165. checkForLeak(&dataUnsupported, rest.Build, rest.Unmarshal, t, expected{jsonType, true, 0, true})
  166. checkForLeak(&dataUnsupported, query.Build, query.UnmarshalMeta, t, expected{jsonType, false, 2048, false})
  167. }
  168. func TestRestJSON(t *testing.T) {
  169. checkForLeak(nil, restjson.Build, restjson.Unmarshal, t, expected{jsonType, true, 0, false})
  170. checkForLeak(nil, restjson.Build, restjson.UnmarshalMeta, t, expected{jsonType, false, 2048, false})
  171. checkForLeak(nil, restjson.Build, restjson.UnmarshalError, t, expected{jsonType, true, 0, true})
  172. }
  173. func TestRestXML(t *testing.T) {
  174. checkForLeak(nil, restxml.Build, restxml.Unmarshal, t, expected{xmlType, true, 0, false})
  175. checkForLeak(nil, restxml.Build, restxml.UnmarshalMeta, t, expected{xmlType, false, 2048, false})
  176. checkForLeak(nil, restxml.Build, restxml.UnmarshalError, t, expected{xmlType, true, 0, true})
  177. }
  178. func TestXML(t *testing.T) {
  179. checkForLeak(nil, ec2query.Build, ec2query.Unmarshal, t, expected{jsonType, true, 0, false})
  180. checkForLeak(nil, ec2query.Build, ec2query.UnmarshalMeta, t, expected{jsonType, false, 2048, false})
  181. checkForLeak(nil, ec2query.Build, ec2query.UnmarshalError, t, expected{jsonType, true, 0, true})
  182. }
  183. func TestProtocol(t *testing.T) {
  184. checkForLeak(nil, restxml.Build, protocol.UnmarshalDiscardBody, t, expected{xmlType, true, 0, false})
  185. }