acs_request.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443
  1. /*
  2. * Licensed under the Apache License, Version 2.0 (the "License");
  3. * you may not use this file except in compliance with the License.
  4. * You may obtain a copy of the License at
  5. *
  6. * http://www.apache.org/licenses/LICENSE-2.0
  7. *
  8. * Unless required by applicable law or agreed to in writing, software
  9. * distributed under the License is distributed on an "AS IS" BASIS,
  10. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. * See the License for the specific language governing permissions and
  12. * limitations under the License.
  13. */
  14. package requests
  15. import (
  16. "encoding/json"
  17. "fmt"
  18. "io"
  19. "reflect"
  20. "strconv"
  21. "strings"
  22. "time"
  23. "github.com/aliyun/alibaba-cloud-sdk-go/sdk/errors"
  24. )
  25. const (
  26. RPC = "RPC"
  27. ROA = "ROA"
  28. HTTP = "HTTP"
  29. HTTPS = "HTTPS"
  30. DefaultHttpPort = "80"
  31. GET = "GET"
  32. PUT = "PUT"
  33. POST = "POST"
  34. DELETE = "DELETE"
  35. PATCH = "PATCH"
  36. HEAD = "HEAD"
  37. OPTIONS = "OPTIONS"
  38. Json = "application/json"
  39. Xml = "application/xml"
  40. Raw = "application/octet-stream"
  41. Form = "application/x-www-form-urlencoded"
  42. Header = "Header"
  43. Query = "Query"
  44. Body = "Body"
  45. Path = "Path"
  46. HeaderSeparator = "\n"
  47. )
  48. // interface
  49. type AcsRequest interface {
  50. GetScheme() string
  51. GetMethod() string
  52. GetDomain() string
  53. GetPort() string
  54. GetRegionId() string
  55. GetHeaders() map[string]string
  56. GetQueryParams() map[string]string
  57. GetFormParams() map[string]string
  58. GetContent() []byte
  59. GetBodyReader() io.Reader
  60. GetStyle() string
  61. GetProduct() string
  62. GetVersion() string
  63. SetVersion(version string)
  64. GetActionName() string
  65. GetAcceptFormat() string
  66. GetLocationServiceCode() string
  67. GetLocationEndpointType() string
  68. GetReadTimeout() time.Duration
  69. GetConnectTimeout() time.Duration
  70. SetReadTimeout(readTimeout time.Duration)
  71. SetConnectTimeout(connectTimeout time.Duration)
  72. SetHTTPSInsecure(isInsecure bool)
  73. GetHTTPSInsecure() *bool
  74. GetUserAgent() map[string]string
  75. SetStringToSign(stringToSign string)
  76. GetStringToSign() string
  77. SetDomain(domain string)
  78. SetContent(content []byte)
  79. SetScheme(scheme string)
  80. BuildUrl() string
  81. BuildQueries() string
  82. addHeaderParam(key, value string)
  83. addQueryParam(key, value string)
  84. addFormParam(key, value string)
  85. addPathParam(key, value string)
  86. }
  87. // base class
  88. type baseRequest struct {
  89. Scheme string
  90. Method string
  91. Domain string
  92. Port string
  93. RegionId string
  94. ReadTimeout time.Duration
  95. ConnectTimeout time.Duration
  96. isInsecure *bool
  97. userAgent map[string]string
  98. product string
  99. version string
  100. actionName string
  101. AcceptFormat string
  102. QueryParams map[string]string
  103. Headers map[string]string
  104. FormParams map[string]string
  105. Content []byte
  106. locationServiceCode string
  107. locationEndpointType string
  108. queries string
  109. stringToSign string
  110. }
  111. func (request *baseRequest) GetQueryParams() map[string]string {
  112. return request.QueryParams
  113. }
  114. func (request *baseRequest) GetFormParams() map[string]string {
  115. return request.FormParams
  116. }
  117. func (request *baseRequest) GetReadTimeout() time.Duration {
  118. return request.ReadTimeout
  119. }
  120. func (request *baseRequest) GetConnectTimeout() time.Duration {
  121. return request.ConnectTimeout
  122. }
  123. func (request *baseRequest) SetReadTimeout(readTimeout time.Duration) {
  124. request.ReadTimeout = readTimeout
  125. }
  126. func (request *baseRequest) SetConnectTimeout(connectTimeout time.Duration) {
  127. request.ConnectTimeout = connectTimeout
  128. }
  129. func (request *baseRequest) GetHTTPSInsecure() *bool {
  130. return request.isInsecure
  131. }
  132. func (request *baseRequest) SetHTTPSInsecure(isInsecure bool) {
  133. request.isInsecure = &isInsecure
  134. }
  135. func (request *baseRequest) GetContent() []byte {
  136. return request.Content
  137. }
  138. func (request *baseRequest) SetVersion(version string) {
  139. request.version = version
  140. }
  141. func (request *baseRequest) GetVersion() string {
  142. return request.version
  143. }
  144. func (request *baseRequest) GetActionName() string {
  145. return request.actionName
  146. }
  147. func (request *baseRequest) SetContent(content []byte) {
  148. request.Content = content
  149. }
  150. func (request *baseRequest) GetUserAgent() map[string]string {
  151. return request.userAgent
  152. }
  153. func (request *baseRequest) AppendUserAgent(key, value string) {
  154. newkey := true
  155. if request.userAgent == nil {
  156. request.userAgent = make(map[string]string)
  157. }
  158. if strings.ToLower(key) != "core" && strings.ToLower(key) != "go" {
  159. for tag, _ := range request.userAgent {
  160. if tag == key {
  161. request.userAgent[tag] = value
  162. newkey = false
  163. }
  164. }
  165. if newkey {
  166. request.userAgent[key] = value
  167. }
  168. }
  169. }
  170. func (request *baseRequest) addHeaderParam(key, value string) {
  171. request.Headers[key] = value
  172. }
  173. func (request *baseRequest) addQueryParam(key, value string) {
  174. request.QueryParams[key] = value
  175. }
  176. func (request *baseRequest) addFormParam(key, value string) {
  177. request.FormParams[key] = value
  178. }
  179. func (request *baseRequest) GetAcceptFormat() string {
  180. return request.AcceptFormat
  181. }
  182. func (request *baseRequest) GetLocationServiceCode() string {
  183. return request.locationServiceCode
  184. }
  185. func (request *baseRequest) GetLocationEndpointType() string {
  186. return request.locationEndpointType
  187. }
  188. func (request *baseRequest) GetProduct() string {
  189. return request.product
  190. }
  191. func (request *baseRequest) GetScheme() string {
  192. return request.Scheme
  193. }
  194. func (request *baseRequest) SetScheme(scheme string) {
  195. request.Scheme = scheme
  196. }
  197. func (request *baseRequest) GetMethod() string {
  198. return request.Method
  199. }
  200. func (request *baseRequest) GetDomain() string {
  201. return request.Domain
  202. }
  203. func (request *baseRequest) SetDomain(host string) {
  204. request.Domain = host
  205. }
  206. func (request *baseRequest) GetPort() string {
  207. return request.Port
  208. }
  209. func (request *baseRequest) GetRegionId() string {
  210. return request.RegionId
  211. }
  212. func (request *baseRequest) GetHeaders() map[string]string {
  213. return request.Headers
  214. }
  215. func (request *baseRequest) SetContentType(contentType string) {
  216. request.addHeaderParam("Content-Type", contentType)
  217. }
  218. func (request *baseRequest) GetContentType() (contentType string, contains bool) {
  219. contentType, contains = request.Headers["Content-Type"]
  220. return
  221. }
  222. func (request *baseRequest) SetStringToSign(stringToSign string) {
  223. request.stringToSign = stringToSign
  224. }
  225. func (request *baseRequest) GetStringToSign() string {
  226. return request.stringToSign
  227. }
  228. func defaultBaseRequest() (request *baseRequest) {
  229. request = &baseRequest{
  230. Scheme: "",
  231. AcceptFormat: "JSON",
  232. Method: GET,
  233. QueryParams: make(map[string]string),
  234. Headers: map[string]string{
  235. "x-sdk-client": "golang/1.0.0",
  236. "x-sdk-invoke-type": "normal",
  237. "Accept-Encoding": "identity",
  238. },
  239. FormParams: make(map[string]string),
  240. }
  241. return
  242. }
  243. func InitParams(request AcsRequest) (err error) {
  244. requestValue := reflect.ValueOf(request).Elem()
  245. err = flatRepeatedList(requestValue, request, "", "")
  246. return
  247. }
  248. func flatRepeatedList(dataValue reflect.Value, request AcsRequest, position, prefix string) (err error) {
  249. dataType := dataValue.Type()
  250. for i := 0; i < dataType.NumField(); i++ {
  251. field := dataType.Field(i)
  252. name, containsNameTag := field.Tag.Lookup("name")
  253. fieldPosition := position
  254. if fieldPosition == "" {
  255. fieldPosition, _ = field.Tag.Lookup("position")
  256. }
  257. typeTag, containsTypeTag := field.Tag.Lookup("type")
  258. if containsNameTag {
  259. if !containsTypeTag {
  260. // simple param
  261. key := prefix + name
  262. value := dataValue.Field(i).String()
  263. if dataValue.Field(i).Kind().String() == "map" {
  264. byt, _ := json.Marshal(dataValue.Field(i).Interface())
  265. value = string(byt)
  266. if value == "null" {
  267. value = ""
  268. }
  269. }
  270. err = addParam(request, fieldPosition, key, value)
  271. if err != nil {
  272. return
  273. }
  274. } else if typeTag == "Repeated" {
  275. // repeated param
  276. err = handleRepeatedParams(request, dataValue, prefix, name, fieldPosition, i)
  277. if err != nil {
  278. return
  279. }
  280. } else if typeTag == "Struct" {
  281. err = handleStruct(request, dataValue, prefix, name, fieldPosition, i)
  282. if err != nil {
  283. return
  284. }
  285. }
  286. }
  287. }
  288. return
  289. }
  290. func handleRepeatedParams(request AcsRequest, dataValue reflect.Value, prefix, name, fieldPosition string, index int) (err error) {
  291. repeatedFieldValue := dataValue.Field(index)
  292. if repeatedFieldValue.Kind() != reflect.Slice {
  293. // possible value: {"[]string", "*[]struct"}, we must call Elem() in the last condition
  294. repeatedFieldValue = repeatedFieldValue.Elem()
  295. }
  296. if repeatedFieldValue.IsValid() && !repeatedFieldValue.IsNil() {
  297. for m := 0; m < repeatedFieldValue.Len(); m++ {
  298. elementValue := repeatedFieldValue.Index(m)
  299. key := prefix + name + "." + strconv.Itoa(m+1)
  300. if elementValue.Type().Kind().String() == "string" {
  301. value := elementValue.String()
  302. err = addParam(request, fieldPosition, key, value)
  303. if err != nil {
  304. return
  305. }
  306. } else {
  307. err = flatRepeatedList(elementValue, request, fieldPosition, key+".")
  308. if err != nil {
  309. return
  310. }
  311. }
  312. }
  313. }
  314. return nil
  315. }
  316. func handleStruct(request AcsRequest, dataValue reflect.Value, prefix, name, fieldPosition string, index int) (err error) {
  317. valueField := dataValue.Field(index)
  318. if valueField.IsValid() && valueField.String() != "" {
  319. valueFieldType := valueField.Type()
  320. for m := 0; m < valueFieldType.NumField(); m++ {
  321. fieldName := valueFieldType.Field(m).Name
  322. elementValue := valueField.FieldByName(fieldName)
  323. key := prefix + name + "." + fieldName
  324. if elementValue.Type().String() == "[]string" {
  325. if elementValue.IsNil() {
  326. continue
  327. }
  328. for j := 0; j < elementValue.Len(); j++ {
  329. err = addParam(request, fieldPosition, key+"."+strconv.Itoa(j+1), elementValue.Index(j).String())
  330. if err != nil {
  331. return
  332. }
  333. }
  334. } else {
  335. if elementValue.Type().Kind().String() == "string" {
  336. value := elementValue.String()
  337. err = addParam(request, fieldPosition, key, value)
  338. if err != nil {
  339. return
  340. }
  341. } else if elementValue.Type().Kind().String() == "struct" {
  342. err = flatRepeatedList(elementValue, request, fieldPosition, key+".")
  343. if err != nil {
  344. return
  345. }
  346. } else if !elementValue.IsNil() {
  347. repeatedFieldValue := elementValue.Elem()
  348. if repeatedFieldValue.IsValid() && !repeatedFieldValue.IsNil() {
  349. for m := 0; m < repeatedFieldValue.Len(); m++ {
  350. elementValue := repeatedFieldValue.Index(m)
  351. err = flatRepeatedList(elementValue, request, fieldPosition, key+"."+strconv.Itoa(m+1)+".")
  352. if err != nil {
  353. return
  354. }
  355. }
  356. }
  357. }
  358. }
  359. }
  360. }
  361. return nil
  362. }
  363. func addParam(request AcsRequest, position, name, value string) (err error) {
  364. if len(value) > 0 {
  365. switch position {
  366. case Header:
  367. request.addHeaderParam(name, value)
  368. case Query:
  369. request.addQueryParam(name, value)
  370. case Path:
  371. request.addPathParam(name, value)
  372. case Body:
  373. request.addFormParam(name, value)
  374. default:
  375. errMsg := fmt.Sprintf(errors.UnsupportedParamPositionErrorMessage, position)
  376. err = errors.NewClientError(errors.UnsupportedParamPositionErrorCode, errMsg, nil)
  377. }
  378. }
  379. return
  380. }