http.go 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981
  1. // Copyright (c) 2016, 2018, 2020, Oracle and/or its affiliates. All rights reserved.
  2. // This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license.
  3. package common
  4. import (
  5. "bytes"
  6. "encoding/json"
  7. "fmt"
  8. "io"
  9. "io/ioutil"
  10. "net/http"
  11. "net/url"
  12. "reflect"
  13. "regexp"
  14. "strconv"
  15. "strings"
  16. "time"
  17. )
  18. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  19. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  20. //Request Marshaling
  21. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  22. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  23. func isNil(v reflect.Value) bool {
  24. return v.Kind() == reflect.Ptr && v.IsNil()
  25. }
  26. // Returns the string representation of a reflect.Value
  27. // Only transforms primitive values
  28. func toStringValue(v reflect.Value, field reflect.StructField) (string, error) {
  29. if v.Kind() == reflect.Ptr {
  30. if v.IsNil() {
  31. return "", fmt.Errorf("can not marshal a nil pointer")
  32. }
  33. v = v.Elem()
  34. }
  35. if v.Type() == timeType {
  36. t := v.Interface().(SDKTime)
  37. return formatTime(t), nil
  38. }
  39. if v.Type() == sdkDateType {
  40. t := v.Interface().(SDKDate)
  41. return formatDate(t), nil
  42. }
  43. switch v.Kind() {
  44. case reflect.Bool:
  45. return strconv.FormatBool(v.Bool()), nil
  46. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  47. return strconv.FormatInt(v.Int(), 10), nil
  48. case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
  49. return strconv.FormatUint(v.Uint(), 10), nil
  50. case reflect.String:
  51. return v.String(), nil
  52. case reflect.Float32:
  53. return strconv.FormatFloat(v.Float(), 'f', -1, 32), nil
  54. case reflect.Float64:
  55. return strconv.FormatFloat(v.Float(), 'f', -1, 64), nil
  56. default:
  57. return "", fmt.Errorf("marshaling structure to a http.Request does not support field named: %s of type: %v",
  58. field.Name, v.Type().String())
  59. }
  60. }
  61. func addBinaryBody(request *http.Request, value reflect.Value, field reflect.StructField) (e error) {
  62. readCloser, ok := value.Interface().(io.ReadCloser)
  63. isMandatory, err := strconv.ParseBool(field.Tag.Get("mandatory"))
  64. if err != nil {
  65. return fmt.Errorf("mandatory tag is not valid for field %s", field.Name)
  66. }
  67. if isMandatory && !ok {
  68. e = fmt.Errorf("body of the request is mandatory and needs to be an io.ReadCloser interface. Can not marshal body of binary request")
  69. return
  70. }
  71. request.Body = readCloser
  72. //Set the default content type to application/octet-stream if not set
  73. if request.Header.Get(requestHeaderContentType) == "" {
  74. request.Header.Set(requestHeaderContentType, "application/octet-stream")
  75. }
  76. return nil
  77. }
  78. // getTaggedNilFieldNameOrError, evaluates if a field with json and non mandatory tags is nil
  79. // returns the json tag name, or an error if the tags are incorrectly present
  80. func getTaggedNilFieldNameOrError(field reflect.StructField, fieldValue reflect.Value) (bool, string, error) {
  81. currentTag := field.Tag
  82. jsonTag := currentTag.Get("json")
  83. if jsonTag == "" {
  84. return false, "", fmt.Errorf("json tag is not valid for field %s", field.Name)
  85. }
  86. partsJSONTag := strings.Split(jsonTag, ",")
  87. nameJSONField := partsJSONTag[0]
  88. if _, ok := currentTag.Lookup("mandatory"); !ok {
  89. //No mandatory field set, no-op
  90. return false, nameJSONField, nil
  91. }
  92. isMandatory, err := strconv.ParseBool(currentTag.Get("mandatory"))
  93. if err != nil {
  94. return false, "", fmt.Errorf("mandatory tag is not valid for field %s", field.Name)
  95. }
  96. // If the field is marked as mandatory, no-op
  97. if isMandatory {
  98. return false, nameJSONField, nil
  99. }
  100. Debugf("Adjusting tag: mandatory is false and json tag is valid on field: %s", field.Name)
  101. // If the field can not be nil, then no-op
  102. if !isNillableType(&fieldValue) {
  103. Debugf("WARNING json field is tagged with mandatory flags, but the type can not be nil, field name: %s", field.Name)
  104. return false, nameJSONField, nil
  105. }
  106. // If field value is nil, tag it as omitEmpty
  107. return fieldValue.IsNil(), nameJSONField, nil
  108. }
  109. // isNillableType returns true if the filed can be nil
  110. func isNillableType(value *reflect.Value) bool {
  111. k := value.Kind()
  112. switch k {
  113. case reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr, reflect.Interface, reflect.Slice:
  114. return true
  115. }
  116. return false
  117. }
  118. // omitNilFieldsInJSON, removes json keys whose struct value is nil, and the field is tagged with the json and
  119. // mandatory:false tags
  120. func omitNilFieldsInJSON(data interface{}, value reflect.Value) (interface{}, error) {
  121. switch value.Kind() {
  122. case reflect.Struct:
  123. jsonMap := data.(map[string]interface{})
  124. fieldType := value.Type()
  125. for i := 0; i < fieldType.NumField(); i++ {
  126. currentField := fieldType.Field(i)
  127. //unexported skip
  128. if currentField.PkgPath != "" {
  129. continue
  130. }
  131. //Does not have json tag, no-op
  132. if _, ok := currentField.Tag.Lookup("json"); !ok {
  133. continue
  134. }
  135. currentFieldValue := value.Field(i)
  136. ok, jsonFieldName, err := getTaggedNilFieldNameOrError(currentField, currentFieldValue)
  137. if err != nil {
  138. return nil, fmt.Errorf("can not omit nil fields for field: %s, due to: %s",
  139. currentField.Name, err.Error())
  140. }
  141. //Delete the struct field from the json representation
  142. if ok {
  143. delete(jsonMap, jsonFieldName)
  144. continue
  145. }
  146. // Check to make sure the field is part of the json representation of the value
  147. if _, contains := jsonMap[jsonFieldName]; !contains {
  148. Debugf("Field %s is not present in json, omitting", jsonFieldName)
  149. continue
  150. }
  151. if currentFieldValue.Type() == timeType || currentFieldValue.Type() == timeTypePtr ||
  152. currentField.Type == sdkDateType || currentField.Type == sdkDateTypePtr {
  153. continue
  154. }
  155. // does it need to be adjusted?
  156. var adjustedValue interface{}
  157. adjustedValue, err = omitNilFieldsInJSON(jsonMap[jsonFieldName], currentFieldValue)
  158. if err != nil {
  159. return nil, fmt.Errorf("can not omit nil fields for field: %s, due to: %s",
  160. currentField.Name, err.Error())
  161. }
  162. jsonMap[jsonFieldName] = adjustedValue
  163. }
  164. return jsonMap, nil
  165. case reflect.Slice, reflect.Array:
  166. // Special case: a []byte may have been marshalled as a string
  167. if data != nil && reflect.TypeOf(data).Kind() == reflect.String && value.Type().Elem().Kind() == reflect.Uint8 {
  168. return data, nil
  169. }
  170. jsonList, ok := data.([]interface{})
  171. if !ok {
  172. return nil, fmt.Errorf("can not omit nil fields, data was expected to be a not-nil list")
  173. }
  174. newList := make([]interface{}, len(jsonList))
  175. var err error
  176. for i, val := range jsonList {
  177. newList[i], err = omitNilFieldsInJSON(val, value.Index(i))
  178. if err != nil {
  179. return nil, err
  180. }
  181. }
  182. return newList, nil
  183. case reflect.Map:
  184. jsonMap, ok := data.(map[string]interface{})
  185. if !ok {
  186. return nil, fmt.Errorf("can not omit nil fields, data was expected to be a not-nil map")
  187. }
  188. newMap := make(map[string]interface{}, len(jsonMap))
  189. var err error
  190. for key, val := range jsonMap {
  191. newMap[key], err = omitNilFieldsInJSON(val, value.MapIndex(reflect.ValueOf(key)))
  192. if err != nil {
  193. return nil, err
  194. }
  195. }
  196. return newMap, nil
  197. case reflect.Ptr, reflect.Interface:
  198. valPtr := value.Elem()
  199. return omitNilFieldsInJSON(data, valPtr)
  200. default:
  201. //Otherwise no-op
  202. return data, nil
  203. }
  204. }
  205. // removeNilFieldsInJSONWithTaggedStruct remove struct fields tagged with json and mandatory false
  206. // that are nil
  207. func removeNilFieldsInJSONWithTaggedStruct(rawJSON []byte, value reflect.Value) ([]byte, error) {
  208. var rawInterface interface{}
  209. decoder := json.NewDecoder(bytes.NewBuffer(rawJSON))
  210. decoder.UseNumber()
  211. var err error
  212. if err = decoder.Decode(&rawInterface); err != nil {
  213. return nil, err
  214. }
  215. fixedMap, err := omitNilFieldsInJSON(rawInterface, value)
  216. if err != nil {
  217. return nil, err
  218. }
  219. return json.Marshal(fixedMap)
  220. }
  221. func addToBody(request *http.Request, value reflect.Value, field reflect.StructField) (e error) {
  222. Debugln("Marshaling to body from field:", field.Name)
  223. if request.Body != nil {
  224. Logf("The body of the request is already set. Structure: %s will overwrite it\n", field.Name)
  225. }
  226. tag := field.Tag
  227. encoding := tag.Get("encoding")
  228. if encoding == "binary" {
  229. return addBinaryBody(request, value, field)
  230. }
  231. rawJSON, e := json.Marshal(value.Interface())
  232. if e != nil {
  233. return
  234. }
  235. marshaled, e := removeNilFieldsInJSONWithTaggedStruct(rawJSON, value)
  236. if e != nil {
  237. return
  238. }
  239. if defaultLogger.LogLevel() == verboseLogging {
  240. Debugf("Marshaled body is: %s\n", string(marshaled))
  241. }
  242. bodyBytes := bytes.NewReader(marshaled)
  243. request.ContentLength = int64(bodyBytes.Len())
  244. request.Header.Set(requestHeaderContentLength, strconv.FormatInt(request.ContentLength, 10))
  245. request.Header.Set(requestHeaderContentType, "application/json")
  246. request.Body = ioutil.NopCloser(bodyBytes)
  247. request.GetBody = func() (io.ReadCloser, error) {
  248. return ioutil.NopCloser(bodyBytes), nil
  249. }
  250. return
  251. }
  252. func addToQuery(request *http.Request, value reflect.Value, field reflect.StructField) (e error) {
  253. Debugln("Marshaling to query from field: ", field.Name)
  254. if request.URL == nil {
  255. request.URL = &url.URL{}
  256. }
  257. query := request.URL.Query()
  258. var queryParameterValue, queryParameterName string
  259. if queryParameterName = field.Tag.Get("name"); queryParameterName == "" {
  260. return fmt.Errorf("marshaling request to a query requires the 'name' tag for field: %s ", field.Name)
  261. }
  262. mandatory, _ := strconv.ParseBool(strings.ToLower(field.Tag.Get("mandatory")))
  263. //If mandatory and nil. Error out
  264. if mandatory && isNil(value) {
  265. return fmt.Errorf("marshaling request to a header requires not nil pointer for field: %s", field.Name)
  266. }
  267. //if not mandatory and nil. Omit
  268. if !mandatory && isNil(value) {
  269. Debugf("Query parameter value is not mandatory and is nil pointer in field: %s. Skipping query", field.Name)
  270. return
  271. }
  272. encoding := strings.ToLower(field.Tag.Get("collectionFormat"))
  273. var collectionFormatStringValues []string
  274. switch encoding {
  275. case "csv", "multi":
  276. if value.Kind() != reflect.Slice && value.Kind() != reflect.Array {
  277. e = fmt.Errorf("query parameter is tagged as csv or multi yet its type is neither an Array nor a Slice: %s", field.Name)
  278. break
  279. }
  280. numOfElements := value.Len()
  281. collectionFormatStringValues = make([]string, numOfElements)
  282. for i := 0; i < numOfElements; i++ {
  283. collectionFormatStringValues[i], e = toStringValue(value.Index(i), field)
  284. if e != nil {
  285. break
  286. }
  287. }
  288. queryParameterValue = strings.Join(collectionFormatStringValues, ",")
  289. case "":
  290. queryParameterValue, e = toStringValue(value, field)
  291. default:
  292. e = fmt.Errorf("encoding of type %s is not supported for query param: %s", encoding, field.Name)
  293. }
  294. if e != nil {
  295. return
  296. }
  297. //check for tag "omitEmpty", this is done to accomodate unset fields that do not
  298. //support an empty string: enums in query params
  299. if omitEmpty, present := field.Tag.Lookup("omitEmpty"); present {
  300. omitEmptyBool, _ := strconv.ParseBool(strings.ToLower(omitEmpty))
  301. if queryParameterValue != "" || !omitEmptyBool {
  302. addToQueryForEncoding(&query, encoding, queryParameterName, queryParameterValue, collectionFormatStringValues)
  303. } else {
  304. Debugf("Omitting %s, is empty and omitEmpty tag is set", field.Name)
  305. }
  306. } else {
  307. addToQueryForEncoding(&query, encoding, queryParameterName, queryParameterValue, collectionFormatStringValues)
  308. }
  309. request.URL.RawQuery = query.Encode()
  310. return
  311. }
  312. func addToQueryForEncoding(query *url.Values, encoding string, queryParameterName string, queryParameterValue string, collectionFormatStringValues []string) {
  313. if encoding == "multi" {
  314. for _, stringValue := range collectionFormatStringValues {
  315. query.Add(queryParameterName, stringValue)
  316. }
  317. } else {
  318. query.Set(queryParameterName, queryParameterValue)
  319. }
  320. }
  321. // Adds to the path of the url in the order they appear in the structure
  322. func addToPath(request *http.Request, value reflect.Value, field reflect.StructField) (e error) {
  323. var additionalURLPathPart string
  324. if additionalURLPathPart, e = toStringValue(value, field); e != nil {
  325. return fmt.Errorf("can not marshal to path in request for field %s. Due to %s", field.Name, e.Error())
  326. }
  327. // path should not be empty for any operations
  328. if len(additionalURLPathPart) == 0 {
  329. return fmt.Errorf("value cannot be empty for field %s in path", field.Name)
  330. }
  331. if request.URL == nil {
  332. request.URL = &url.URL{}
  333. request.URL.Path = ""
  334. }
  335. var currentURLPath = request.URL.Path
  336. var templatedPathRegex, _ = regexp.Compile(".*{.+}.*")
  337. if !templatedPathRegex.MatchString(currentURLPath) {
  338. Debugln("Marshaling request to path by appending field:", field.Name)
  339. allPath := []string{currentURLPath, additionalURLPathPart}
  340. request.URL.Path = strings.Join(allPath, "/")
  341. } else {
  342. var fieldName string
  343. if fieldName = field.Tag.Get("name"); fieldName == "" {
  344. e = fmt.Errorf("marshaling request to path name and template requires a 'name' tag for field: %s", field.Name)
  345. return
  346. }
  347. urlTemplate := currentURLPath
  348. Debugln("Marshaling to path from field: ", field.Name, " in template: ", urlTemplate)
  349. request.URL.Path = strings.Replace(urlTemplate, "{"+fieldName+"}", additionalURLPathPart, -1)
  350. }
  351. return
  352. }
  353. func setWellKnownHeaders(request *http.Request, headerName, headerValue string) (e error) {
  354. switch strings.ToLower(headerName) {
  355. case "content-length":
  356. var len int
  357. len, e = strconv.Atoi(headerValue)
  358. if e != nil {
  359. return
  360. }
  361. request.ContentLength = int64(len)
  362. }
  363. return nil
  364. }
  365. func addToHeader(request *http.Request, value reflect.Value, field reflect.StructField) (e error) {
  366. Debugln("Marshaling to header from field: ", field.Name)
  367. if request.Header == nil {
  368. request.Header = http.Header{}
  369. }
  370. var headerName, headerValue string
  371. if headerName = field.Tag.Get("name"); headerName == "" {
  372. return fmt.Errorf("marshaling request to a header requires the 'name' tag for field: %s", field.Name)
  373. }
  374. mandatory, _ := strconv.ParseBool(strings.ToLower(field.Tag.Get("mandatory")))
  375. //If mandatory and nil. Error out
  376. if mandatory && isNil(value) {
  377. return fmt.Errorf("marshaling request to a header requires not nil pointer for field: %s", field.Name)
  378. }
  379. // generate opc-request-id if header value is nil and header name matches
  380. value = generateOpcRequestID(headerName, value)
  381. //if not mandatory and nil. Omit
  382. if !mandatory && isNil(value) {
  383. Debugf("Header value is not mandatory and is nil pointer in field: %s. Skipping header", field.Name)
  384. return
  385. }
  386. //Otherwise get value and set header
  387. if headerValue, e = toStringValue(value, field); e != nil {
  388. return
  389. }
  390. if e = setWellKnownHeaders(request, headerName, headerValue); e != nil {
  391. return
  392. }
  393. if isUniqueHeaderRequired(headerName) {
  394. request.Header.Set(headerName, headerValue)
  395. } else {
  396. request.Header.Add(headerName, headerValue)
  397. }
  398. return
  399. }
  400. // Check if the header is required to be unique
  401. func isUniqueHeaderRequired(headerName string) bool {
  402. return strings.EqualFold(headerName, requestHeaderContentType)
  403. }
  404. // Header collection is a map of string to string that gets rendered as individual headers with a given prefix
  405. func addToHeaderCollection(request *http.Request, value reflect.Value, field reflect.StructField) (e error) {
  406. Debugln("Marshaling to header-collection from field:", field.Name)
  407. if request.Header == nil {
  408. request.Header = http.Header{}
  409. }
  410. var headerPrefix string
  411. if headerPrefix = field.Tag.Get("prefix"); headerPrefix == "" {
  412. return fmt.Errorf("marshaling request to a header requires the 'prefix' tag for field: %s", field.Name)
  413. }
  414. mandatory, _ := strconv.ParseBool(strings.ToLower(field.Tag.Get("mandatory")))
  415. //If mandatory and nil. Error out
  416. if mandatory && isNil(value) {
  417. return fmt.Errorf("marshaling request to a header requires not nil pointer for field: %s", field.Name)
  418. }
  419. //if not mandatory and nil. Omit
  420. if !mandatory && isNil(value) {
  421. Debugf("Header value is not mandatory and is nil pointer in field: %s. Skipping header", field.Name)
  422. return
  423. }
  424. //cast to map
  425. headerValues, ok := value.Interface().(map[string]string)
  426. if !ok {
  427. e = fmt.Errorf("header fields need to be of type map[string]string")
  428. return
  429. }
  430. for k, v := range headerValues {
  431. headerName := fmt.Sprintf("%s%s", headerPrefix, k)
  432. request.Header.Set(headerName, v)
  433. }
  434. return
  435. }
  436. // Makes sure the incoming structure is able to be marshalled
  437. // to a request
  438. func checkForValidRequestStruct(s interface{}) (*reflect.Value, error) {
  439. val := reflect.ValueOf(s)
  440. for val.Kind() == reflect.Ptr {
  441. if val.IsNil() {
  442. return nil, fmt.Errorf("can not marshal to request a pointer to structure")
  443. }
  444. val = val.Elem()
  445. }
  446. if s == nil {
  447. return nil, fmt.Errorf("can not marshal to request a nil structure")
  448. }
  449. if val.Kind() != reflect.Struct {
  450. return nil, fmt.Errorf("can not marshal to request, expects struct input. Got %v", val.Kind())
  451. }
  452. return &val, nil
  453. }
  454. // Populates the parts of a request by reading tags in the passed structure
  455. // nested structs are followed recursively depth-first.
  456. func structToRequestPart(request *http.Request, val reflect.Value) (err error) {
  457. typ := val.Type()
  458. for i := 0; i < typ.NumField(); i++ {
  459. if err != nil {
  460. return
  461. }
  462. sf := typ.Field(i)
  463. //unexported
  464. if sf.PkgPath != "" && !sf.Anonymous {
  465. continue
  466. }
  467. sv := val.Field(i)
  468. tag := sf.Tag.Get("contributesTo")
  469. switch tag {
  470. case "header":
  471. err = addToHeader(request, sv, sf)
  472. case "header-collection":
  473. err = addToHeaderCollection(request, sv, sf)
  474. case "path":
  475. err = addToPath(request, sv, sf)
  476. case "query":
  477. err = addToQuery(request, sv, sf)
  478. case "body":
  479. err = addToBody(request, sv, sf)
  480. case "":
  481. Debugln(sf.Name, " does not contain contributes tag. Skipping.")
  482. default:
  483. err = fmt.Errorf("can not marshal field: %s. It needs to contain valid contributesTo tag", sf.Name)
  484. }
  485. }
  486. //If headers are and the content type was not set, we default to application/json
  487. if request.Header != nil && request.Header.Get(requestHeaderContentType) == "" {
  488. request.Header.Set(requestHeaderContentType, "application/json")
  489. }
  490. return
  491. }
  492. // HTTPRequestMarshaller marshals a structure to an http request using tag values in the struct
  493. // The marshaller tag should like the following
  494. // type A struct {
  495. // ANumber string `contributesTo="query" name="number"`
  496. // TheBody `contributesTo="body"`
  497. // }
  498. // where the contributesTo tag can be: header, path, query, body
  499. // and the 'name' tag is the name of the value used in the http request(not applicable for path)
  500. // If path is specified as part of the tag, the values are appened to the url path
  501. // in the order they appear in the structure
  502. // The current implementation only supports primitive types, except for the body tag, which needs a struct type.
  503. // The body of a request will be marshaled using the tags of the structure
  504. func HTTPRequestMarshaller(requestStruct interface{}, httpRequest *http.Request) (err error) {
  505. var val *reflect.Value
  506. if val, err = checkForValidRequestStruct(requestStruct); err != nil {
  507. return
  508. }
  509. Debugln("Marshaling to Request: ", val.Type().Name())
  510. err = structToRequestPart(httpRequest, *val)
  511. return
  512. }
  513. // MakeDefaultHTTPRequest creates the basic http request with the necessary headers set
  514. func MakeDefaultHTTPRequest(method, path string) (httpRequest http.Request) {
  515. httpRequest = http.Request{
  516. Proto: "HTTP/1.1",
  517. ProtoMajor: 1,
  518. ProtoMinor: 1,
  519. Header: make(http.Header),
  520. URL: &url.URL{},
  521. }
  522. httpRequest.Header.Set(requestHeaderContentLength, "0")
  523. httpRequest.Header.Set(requestHeaderDate, time.Now().UTC().Format(http.TimeFormat))
  524. httpRequest.Header.Set(requestHeaderOpcClientInfo, strings.Join([]string{defaultSDKMarker, Version()}, "/"))
  525. httpRequest.Header.Set(requestHeaderAccept, "*/*")
  526. httpRequest.Method = method
  527. httpRequest.URL.Path = path
  528. return
  529. }
  530. // MakeDefaultHTTPRequestWithTaggedStruct creates an http request from an struct with tagged fields, see HTTPRequestMarshaller
  531. // for more information
  532. func MakeDefaultHTTPRequestWithTaggedStruct(method, path string, requestStruct interface{}) (httpRequest http.Request, err error) {
  533. httpRequest = MakeDefaultHTTPRequest(method, path)
  534. err = HTTPRequestMarshaller(requestStruct, &httpRequest)
  535. return
  536. }
  537. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  538. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  539. //Request UnMarshaling
  540. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  541. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  542. // Makes sure the incoming structure is able to be unmarshaled
  543. // to a request
  544. func checkForValidResponseStruct(s interface{}) (*reflect.Value, error) {
  545. val := reflect.ValueOf(s)
  546. for val.Kind() == reflect.Ptr {
  547. if val.IsNil() {
  548. return nil, fmt.Errorf("can not unmarshal to response a pointer to nil structure")
  549. }
  550. val = val.Elem()
  551. }
  552. if s == nil {
  553. return nil, fmt.Errorf("can not unmarshal to response a nil structure")
  554. }
  555. if val.Kind() != reflect.Struct {
  556. return nil, fmt.Errorf("can not unmarshal to response, expects struct input. Got %v", val.Kind())
  557. }
  558. return &val, nil
  559. }
  560. func intSizeFromKind(kind reflect.Kind) int {
  561. switch kind {
  562. case reflect.Int8, reflect.Uint8:
  563. return 8
  564. case reflect.Int16, reflect.Uint16:
  565. return 16
  566. case reflect.Int32, reflect.Uint32:
  567. return 32
  568. case reflect.Int64, reflect.Uint64:
  569. return 64
  570. case reflect.Int, reflect.Uint:
  571. return strconv.IntSize
  572. default:
  573. Debugf("The type is not valid: %v. Returing int size for arch\n", kind.String())
  574. return strconv.IntSize
  575. }
  576. }
  577. func analyzeValue(stringValue string, kind reflect.Kind, field reflect.StructField) (val reflect.Value, valPointer reflect.Value, err error) {
  578. switch kind {
  579. case timeType.Kind():
  580. var t time.Time
  581. t, err = tryParsingTimeWithValidFormatsForHeaders([]byte(stringValue), field.Name)
  582. if err != nil {
  583. return
  584. }
  585. sdkTime := sdkTimeFromTime(t)
  586. val = reflect.ValueOf(sdkTime)
  587. valPointer = reflect.ValueOf(&sdkTime)
  588. return
  589. case sdkDateType.Kind():
  590. var t time.Time
  591. t, err = tryParsingTimeWithValidFormatsForHeaders([]byte(stringValue), field.Name)
  592. if err != nil {
  593. return
  594. }
  595. sdkDate := sdkDateFromTime(t)
  596. val = reflect.ValueOf(sdkDate)
  597. valPointer = reflect.ValueOf(&sdkDate)
  598. return
  599. case reflect.Bool:
  600. var bVal bool
  601. if bVal, err = strconv.ParseBool(stringValue); err != nil {
  602. return
  603. }
  604. val = reflect.ValueOf(bVal)
  605. valPointer = reflect.ValueOf(&bVal)
  606. return
  607. case reflect.Int:
  608. size := intSizeFromKind(kind)
  609. var iVal int64
  610. if iVal, err = strconv.ParseInt(stringValue, 10, size); err != nil {
  611. return
  612. }
  613. var iiVal int
  614. iiVal = int(iVal)
  615. val = reflect.ValueOf(iiVal)
  616. valPointer = reflect.ValueOf(&iiVal)
  617. return
  618. case reflect.Int64:
  619. size := intSizeFromKind(kind)
  620. var iVal int64
  621. if iVal, err = strconv.ParseInt(stringValue, 10, size); err != nil {
  622. return
  623. }
  624. val = reflect.ValueOf(iVal)
  625. valPointer = reflect.ValueOf(&iVal)
  626. return
  627. case reflect.Uint:
  628. size := intSizeFromKind(kind)
  629. var iVal uint64
  630. if iVal, err = strconv.ParseUint(stringValue, 10, size); err != nil {
  631. return
  632. }
  633. var uiVal uint
  634. uiVal = uint(iVal)
  635. val = reflect.ValueOf(uiVal)
  636. valPointer = reflect.ValueOf(&uiVal)
  637. return
  638. case reflect.String:
  639. val = reflect.ValueOf(stringValue)
  640. valPointer = reflect.ValueOf(&stringValue)
  641. case reflect.Float32:
  642. var fVal float64
  643. if fVal, err = strconv.ParseFloat(stringValue, 32); err != nil {
  644. return
  645. }
  646. var ffVal float32
  647. ffVal = float32(fVal)
  648. val = reflect.ValueOf(ffVal)
  649. valPointer = reflect.ValueOf(&ffVal)
  650. return
  651. case reflect.Float64:
  652. var fVal float64
  653. if fVal, err = strconv.ParseFloat(stringValue, 64); err != nil {
  654. return
  655. }
  656. val = reflect.ValueOf(fVal)
  657. valPointer = reflect.ValueOf(&fVal)
  658. return
  659. default:
  660. err = fmt.Errorf("value for kind: %s not supported", kind)
  661. }
  662. return
  663. }
  664. // Sets the field of a struct, with the appropiate value of the string
  665. // Only sets basic types
  666. func fromStringValue(newValue string, val *reflect.Value, field reflect.StructField) (err error) {
  667. if !val.CanSet() {
  668. err = fmt.Errorf("can not set field name: %s of type: %v", field.Name, val.Type().String())
  669. return
  670. }
  671. kind := val.Kind()
  672. isPointer := false
  673. if val.Kind() == reflect.Ptr {
  674. isPointer = true
  675. kind = field.Type.Elem().Kind()
  676. }
  677. value, valPtr, err := analyzeValue(newValue, kind, field)
  678. if err != nil {
  679. return
  680. }
  681. if !isPointer {
  682. val.Set(value)
  683. } else {
  684. val.Set(valPtr)
  685. }
  686. return
  687. }
  688. // PolymorphicJSONUnmarshaler is the interface to unmarshal polymorphic json payloads
  689. type PolymorphicJSONUnmarshaler interface {
  690. UnmarshalPolymorphicJSON(data []byte) (interface{}, error)
  691. }
  692. func valueFromPolymorphicJSON(content []byte, unmarshaler PolymorphicJSONUnmarshaler) (val interface{}, err error) {
  693. err = json.Unmarshal(content, unmarshaler)
  694. if err != nil {
  695. return
  696. }
  697. val, err = unmarshaler.UnmarshalPolymorphicJSON(content)
  698. return
  699. }
  700. func valueFromJSONBody(response *http.Response, value *reflect.Value, unmarshaler PolymorphicJSONUnmarshaler) (val interface{}, err error) {
  701. //Consumes the body, consider implementing it
  702. //without body consumption
  703. var content []byte
  704. content, err = ioutil.ReadAll(response.Body)
  705. if err != nil {
  706. return
  707. }
  708. if unmarshaler != nil {
  709. val, err = valueFromPolymorphicJSON(content, unmarshaler)
  710. return
  711. }
  712. val = reflect.New(value.Type()).Interface()
  713. err = json.Unmarshal(content, &val)
  714. return
  715. }
  716. func addFromBody(response *http.Response, value *reflect.Value, field reflect.StructField, unmarshaler PolymorphicJSONUnmarshaler) (err error) {
  717. Debugln("Unmarshaling from body to field: ", field.Name)
  718. if response.Body == nil {
  719. Debugln("Unmarshaling body skipped due to nil body content for field: ", field.Name)
  720. return nil
  721. }
  722. tag := field.Tag
  723. encoding := tag.Get("encoding")
  724. var iVal interface{}
  725. switch encoding {
  726. case "binary":
  727. value.Set(reflect.ValueOf(response.Body))
  728. return
  729. case "plain-text":
  730. //Expects UTF-8
  731. byteArr, e := ioutil.ReadAll(response.Body)
  732. if e != nil {
  733. return e
  734. }
  735. str := string(byteArr)
  736. value.Set(reflect.ValueOf(&str))
  737. return
  738. default: //If the encoding is not set. we'll decode with json
  739. iVal, err = valueFromJSONBody(response, value, unmarshaler)
  740. if err != nil {
  741. return
  742. }
  743. newVal := reflect.ValueOf(iVal)
  744. if newVal.Kind() == reflect.Ptr {
  745. newVal = newVal.Elem()
  746. }
  747. value.Set(newVal)
  748. return
  749. }
  750. }
  751. func addFromHeader(response *http.Response, value *reflect.Value, field reflect.StructField) (err error) {
  752. Debugln("Unmarshaling from header to field: ", field.Name)
  753. var headerName string
  754. if headerName = field.Tag.Get("name"); headerName == "" {
  755. return fmt.Errorf("unmarshaling response to a header requires the 'name' tag for field: %s", field.Name)
  756. }
  757. headerValue := response.Header.Get(headerName)
  758. if headerValue == "" {
  759. Debugf("Unmarshalling did not find header with name:%s", headerName)
  760. return nil
  761. }
  762. if err = fromStringValue(headerValue, value, field); err != nil {
  763. return fmt.Errorf("unmarshaling response to a header failed for field %s, due to %s", field.Name,
  764. err.Error())
  765. }
  766. return
  767. }
  768. func addFromHeaderCollection(response *http.Response, value *reflect.Value, field reflect.StructField) error {
  769. Debugln("Unmarshaling from header-collection to field:", field.Name)
  770. var headerPrefix string
  771. if headerPrefix = field.Tag.Get("prefix"); headerPrefix == "" {
  772. return fmt.Errorf("Unmarshaling response to a header-collection requires the 'prefix' tag for field: %s", field.Name)
  773. }
  774. mapCollection := make(map[string]string)
  775. for name, value := range response.Header {
  776. nameLowerCase := strings.ToLower(name)
  777. if strings.HasPrefix(nameLowerCase, headerPrefix) {
  778. headerNoPrefix := strings.TrimPrefix(nameLowerCase, headerPrefix)
  779. mapCollection[headerNoPrefix] = value[0]
  780. }
  781. }
  782. Debugln("Marshalled header collection is:", mapCollection)
  783. value.Set(reflect.ValueOf(mapCollection))
  784. return nil
  785. }
  786. // Populates a struct from parts of a request by reading tags of the struct
  787. func responseToStruct(response *http.Response, val *reflect.Value, unmarshaler PolymorphicJSONUnmarshaler) (err error) {
  788. typ := val.Type()
  789. for i := 0; i < typ.NumField(); i++ {
  790. if err != nil {
  791. return
  792. }
  793. sf := typ.Field(i)
  794. //unexported
  795. if sf.PkgPath != "" {
  796. continue
  797. }
  798. sv := val.Field(i)
  799. tag := sf.Tag.Get("presentIn")
  800. switch tag {
  801. case "header":
  802. err = addFromHeader(response, &sv, sf)
  803. case "header-collection":
  804. err = addFromHeaderCollection(response, &sv, sf)
  805. case "body":
  806. err = addFromBody(response, &sv, sf, unmarshaler)
  807. case "":
  808. Debugln(sf.Name, " does not contain presentIn tag. Skipping")
  809. default:
  810. err = fmt.Errorf("can not unmarshal field: %s. It needs to contain valid presentIn tag", sf.Name)
  811. }
  812. }
  813. return
  814. }
  815. // UnmarshalResponse hydrates the fields of a struct with the values of a http response, guided
  816. // by the field tags. The directive tag is "presentIn" and it can be either
  817. // - "header": Will look for the header tagged as "name" in the headers of the struct and set it value to that
  818. // - "body": It will try to marshal the body from a json string to a struct tagged with 'presentIn: "body"'.
  819. // Further this method will consume the body it should be safe to close it after this function
  820. // Notice the current implementation only supports native types:int, strings, floats, bool as the field types
  821. func UnmarshalResponse(httpResponse *http.Response, responseStruct interface{}) (err error) {
  822. var val *reflect.Value
  823. if val, err = checkForValidResponseStruct(responseStruct); err != nil {
  824. return
  825. }
  826. if err = responseToStruct(httpResponse, val, nil); err != nil {
  827. return
  828. }
  829. return nil
  830. }
  831. // UnmarshalResponseWithPolymorphicBody similar to UnmarshalResponse but assumes the body of the response
  832. // contains polymorphic json. This function will use the unmarshaler argument to unmarshal json content
  833. func UnmarshalResponseWithPolymorphicBody(httpResponse *http.Response, responseStruct interface{}, unmarshaler PolymorphicJSONUnmarshaler) (err error) {
  834. var val *reflect.Value
  835. if val, err = checkForValidResponseStruct(responseStruct); err != nil {
  836. return
  837. }
  838. if err = responseToStruct(httpResponse, val, unmarshaler); err != nil {
  839. return
  840. }
  841. return nil
  842. }
  843. // generate request id if user not provided and for each retry operation re-gen a new request id
  844. func generateOpcRequestID(headerName string, value reflect.Value) (newValue reflect.Value) {
  845. newValue = value
  846. isNilValue := isNil(newValue)
  847. isOpcRequestIDHeader := headerName == requestHeaderOpcRequestID || headerName == requestHeaderOpcClientRequestID
  848. if isNilValue && isOpcRequestIDHeader {
  849. requestID, err := generateRandUUID()
  850. if err != nil {
  851. // this will not fail the request, just skip add opc-request-id
  852. Debugf("unable to generate opc-request-id. %s", err.Error())
  853. } else {
  854. newValue = reflect.ValueOf(String(requestID))
  855. Debugf("add request id for header: %s, with value: %s", headerName, requestID)
  856. }
  857. }
  858. return
  859. }