http.go raw

   1  // Copyright (c) 2016, 2018, 2025, 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  
   4  package common
   5  
   6  import (
   7  	"bytes"
   8  	"encoding/json"
   9  	"fmt"
  10  	"io"
  11  	"io/ioutil"
  12  	"net/http"
  13  	"net/url"
  14  	"os"
  15  	"reflect"
  16  	"regexp"
  17  	"strconv"
  18  	"strings"
  19  	"time"
  20  )
  21  
  22  const (
  23  	//UsingExpectHeaderEnvVar is the key to determine whether expect 100-continue is enabled or not
  24  	UsingExpectHeaderEnvVar = "OCI_GOSDK_USING_EXPECT_HEADER"
  25  	//EncodePathParamsEnvVar determines if special characters in path params such as / and & are URL encoded
  26  	EncodePathParamsEnvVar = "OCI_GOSDK_ENCODE_PATH_PARAMS"
  27  	// EscapeJSONToASCIIEnvVar determines if non-ASCII characters in JSON strings are escaped
  28  	EscapeJSONToASCIIEnvVar = "OCI_GOSDK_ESCAPE_JSON_ASCII"
  29  )
  30  
  31  ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  32  ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  33  //Request Marshaling
  34  ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  35  ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  36  
  37  func isNil(v reflect.Value) bool {
  38  	return v.Kind() == reflect.Ptr && v.IsNil()
  39  }
  40  
  41  // Returns the string representation of a reflect.Value
  42  // Only transforms primitive values
  43  func toStringValue(v reflect.Value, field reflect.StructField) (string, error) {
  44  	if v.Kind() == reflect.Ptr {
  45  		if v.IsNil() {
  46  			return "", fmt.Errorf("can not marshal a nil pointer")
  47  		}
  48  		v = v.Elem()
  49  	}
  50  
  51  	if v.Type() == timeType {
  52  		t := v.Interface().(SDKTime)
  53  		return formatTime(t), nil
  54  	}
  55  
  56  	if v.Type() == sdkDateType {
  57  		t := v.Interface().(SDKDate)
  58  		return formatDate(t), nil
  59  	}
  60  
  61  	switch v.Kind() {
  62  	case reflect.Bool:
  63  		return strconv.FormatBool(v.Bool()), nil
  64  	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  65  		return strconv.FormatInt(v.Int(), 10), nil
  66  	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
  67  		return strconv.FormatUint(v.Uint(), 10), nil
  68  	case reflect.String:
  69  		return v.String(), nil
  70  	case reflect.Float32:
  71  		return strconv.FormatFloat(v.Float(), 'f', -1, 32), nil
  72  	case reflect.Float64:
  73  		return strconv.FormatFloat(v.Float(), 'f', -1, 64), nil
  74  	default:
  75  		return "", fmt.Errorf("marshaling structure to a http.Request does not support field named: %s of type: %v",
  76  			field.Name, v.Type().String())
  77  	}
  78  }
  79  
  80  func addBinaryBody(request *http.Request, value reflect.Value, field reflect.StructField) (e error) {
  81  	readCloser, ok := value.Interface().(io.ReadCloser)
  82  	isMandatory, err := strconv.ParseBool(field.Tag.Get("mandatory"))
  83  	if err != nil {
  84  		return fmt.Errorf("mandatory tag is not valid for field %s", field.Name)
  85  	}
  86  
  87  	if isMandatory && !ok {
  88  		e = fmt.Errorf("body of the request is mandatory and needs to be an io.ReadCloser interface. Can not marshal body of binary request")
  89  		return
  90  	}
  91  
  92  	request.Body = readCloser
  93  
  94  	//Set the default content type to application/octet-stream if not set
  95  	if request.Header.Get(requestHeaderContentType) == "" {
  96  		request.Header.Set(requestHeaderContentType, "application/octet-stream")
  97  	}
  98  	return nil
  99  }
 100  
 101  // getTaggedNilFieldNameOrError, evaluates if a field with json and  non mandatory tags is nil
 102  // returns the json tag name, or an error if the tags are incorrectly present
 103  func getTaggedNilFieldNameOrError(field reflect.StructField, fieldValue reflect.Value) (bool, string, error) {
 104  	currentTag := field.Tag
 105  	jsonTag := currentTag.Get("json")
 106  
 107  	if jsonTag == "" {
 108  		return false, "", fmt.Errorf("json tag is not valid for field %s", field.Name)
 109  	}
 110  
 111  	partsJSONTag := strings.Split(jsonTag, ",")
 112  	nameJSONField := partsJSONTag[0]
 113  
 114  	if _, ok := currentTag.Lookup("mandatory"); !ok {
 115  		//No mandatory field set, no-op
 116  		return false, nameJSONField, nil
 117  	}
 118  	isMandatory, err := strconv.ParseBool(currentTag.Get("mandatory"))
 119  	if err != nil {
 120  		return false, "", fmt.Errorf("mandatory tag is not valid for field %s", field.Name)
 121  	}
 122  
 123  	// If the field is marked as mandatory, no-op
 124  	if isMandatory {
 125  		return false, nameJSONField, nil
 126  	}
 127  
 128  	Debugf("Adjusting tag: mandatory is false and json tag is valid on field: %s", field.Name)
 129  
 130  	// If the field can not be nil, then no-op
 131  	if !isNillableType(&fieldValue) {
 132  		Debugf("WARNING json field is tagged with mandatory flags, but the type can not be nil, field name: %s", field.Name)
 133  		return false, nameJSONField, nil
 134  	}
 135  
 136  	// If field value is nil, tag it as omitEmpty
 137  	return fieldValue.IsNil(), nameJSONField, nil
 138  
 139  }
 140  
 141  // isNillableType returns true if the filed can be nil
 142  func isNillableType(value *reflect.Value) bool {
 143  	k := value.Kind()
 144  	switch k {
 145  	case reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr, reflect.Interface, reflect.Slice:
 146  		return true
 147  	}
 148  	return false
 149  }
 150  
 151  // omitNilFieldsInJSON, removes json keys whose struct value is nil, and the field is tagged with the json and
 152  // mandatory:false tags
 153  func omitNilFieldsInJSON(data interface{}, value reflect.Value) (interface{}, error) {
 154  	switch value.Kind() {
 155  	case reflect.Struct:
 156  		jsonMap := data.(map[string]interface{})
 157  		fieldType := value.Type()
 158  		for i := 0; i < fieldType.NumField(); i++ {
 159  			currentField := fieldType.Field(i)
 160  			//unexported skip
 161  			if currentField.PkgPath != "" {
 162  				continue
 163  			}
 164  
 165  			//Does not have json tag, no-op
 166  			if _, ok := currentField.Tag.Lookup("json"); !ok {
 167  				continue
 168  			}
 169  
 170  			currentFieldValue := value.Field(i)
 171  			ok, jsonFieldName, err := getTaggedNilFieldNameOrError(currentField, currentFieldValue)
 172  			if err != nil {
 173  				return nil, fmt.Errorf("can not omit nil fields for field: %s, due to: %s",
 174  					currentField.Name, err.Error())
 175  			}
 176  
 177  			//Delete the struct field from the json representation
 178  			if ok {
 179  				delete(jsonMap, jsonFieldName)
 180  				continue
 181  			}
 182  
 183  			// Check to make sure the field is part of the json representation of the value
 184  			if _, contains := jsonMap[jsonFieldName]; !contains {
 185  				Debugf("Field %s is not present in json, omitting", jsonFieldName)
 186  				continue
 187  			}
 188  
 189  			if currentFieldValue.Type() == timeType || currentFieldValue.Type() == timeTypePtr ||
 190  				currentField.Type == sdkDateType || currentField.Type == sdkDateTypePtr {
 191  				continue
 192  			}
 193  			// does it need to be adjusted?
 194  			var adjustedValue interface{}
 195  			adjustedValue, err = omitNilFieldsInJSON(jsonMap[jsonFieldName], currentFieldValue)
 196  			if err != nil {
 197  				return nil, fmt.Errorf("can not omit nil fields for field: %s, due to: %s",
 198  					currentField.Name, err.Error())
 199  			}
 200  			jsonMap[jsonFieldName] = adjustedValue
 201  		}
 202  		return jsonMap, nil
 203  	case reflect.Slice, reflect.Array:
 204  		// Special case: a []byte may have been marshalled as a string
 205  		if data != nil && reflect.TypeOf(data).Kind() == reflect.String && value.Type().Elem().Kind() == reflect.Uint8 {
 206  			return data, nil
 207  		}
 208  		jsonList, ok := data.([]interface{})
 209  		if !ok {
 210  			return nil, fmt.Errorf("can not omit nil fields, data was expected to be a not-nil list")
 211  		}
 212  		newList := make([]interface{}, len(jsonList))
 213  		var err error
 214  		for i, val := range jsonList {
 215  			newList[i], err = omitNilFieldsInJSON(val, value.Index(i))
 216  			if err != nil {
 217  				return nil, err
 218  			}
 219  		}
 220  		return newList, nil
 221  	case reflect.Map:
 222  		jsonMap, ok := data.(map[string]interface{})
 223  		if !ok {
 224  			return nil, fmt.Errorf("can not omit nil fields, data was expected to be a not-nil map")
 225  		}
 226  		newMap := make(map[string]interface{}, len(jsonMap))
 227  		var err error
 228  		for key, val := range jsonMap {
 229  			newMap[key], err = omitNilFieldsInJSON(val, value.MapIndex(reflect.ValueOf(key)))
 230  			if err != nil {
 231  				return nil, err
 232  			}
 233  		}
 234  		return newMap, nil
 235  	case reflect.Ptr, reflect.Interface:
 236  		valPtr := value.Elem()
 237  		return omitNilFieldsInJSON(data, valPtr)
 238  	default:
 239  		//Otherwise no-op
 240  		return data, nil
 241  	}
 242  }
 243  
 244  // removeNilFieldsInJSONWithTaggedStruct remove struct fields tagged with json and mandatory false
 245  // that are nil
 246  func removeNilFieldsInJSONWithTaggedStruct(rawJSON []byte, value reflect.Value) ([]byte, error) {
 247  	var rawInterface interface{}
 248  	decoder := json.NewDecoder(bytes.NewBuffer(rawJSON))
 249  	decoder.UseNumber()
 250  	var err error
 251  	if err = decoder.Decode(&rawInterface); err != nil {
 252  		return nil, err
 253  	}
 254  
 255  	fixedMap, err := omitNilFieldsInJSON(rawInterface, value)
 256  	if err != nil {
 257  		return nil, err
 258  	}
 259  	return json.Marshal(fixedMap)
 260  }
 261  
 262  // escapeJSONToASCII takes a JSON payload and returns an equivalent JSON where all string values are escaped to ASCII
 263  func escapeJSONToASCII(rawJSON []byte) ([]byte, error) {
 264  	var rawInterface interface{}
 265  	decoder := json.NewDecoder(bytes.NewReader(rawJSON))
 266  	decoder.UseNumber()
 267  	if err := decoder.Decode(&rawInterface); err != nil {
 268  		return nil, err
 269  	}
 270  
 271  	// transform recursively visits the JSON value:
 272  	// 		- For objects (map[string[interface{}]]), recurse on each value
 273  	// 		- For arrays ([]interface{}), recurse on each element
 274  	// 		- For strings, produce a JSON-quoted ASCII-only representation
 275  	// 		- For other types, return as is
 276  	var transform func(interface{}) interface{}
 277  	transform = func(x interface{}) interface{} {
 278  		switch t := x.(type) {
 279  		case map[string]interface{}:
 280  			m := make(map[string]interface{}, len(t))
 281  			for key, val := range t {
 282  				m[key] = transform(val)
 283  			}
 284  			return m
 285  		case []interface{}:
 286  			s := make([]interface{}, len(t))
 287  			for i, val := range t {
 288  				s[i] = transform(val)
 289  			}
 290  			return s
 291  		case string:
 292  			// QuoteToASCII returns a 'quoted' JSON string containing only ASCII characters
 293  			// ex: input: "ハッピー" -> "\"\\u30cf\\u30c3\\u30d4\\u30fc\""
 294  			// Returns as json.RawMessage so it gets embedded directly
 295  			q := strconv.AppendQuoteToASCII(nil, t)
 296  			return json.RawMessage(q)
 297  		default:
 298  			return x
 299  		}
 300  	}
 301  
 302  	return json.Marshal(transform(rawInterface))
 303  }
 304  
 305  func addToBody(request *http.Request, value reflect.Value, field reflect.StructField, binaryBodySpecified *bool) (e error) {
 306  	Debugln("Marshaling to body from field:", field.Name)
 307  	if request.Body != nil {
 308  		Logf("The body of the request is already set. Structure: %s will overwrite it\n", field.Name)
 309  	}
 310  	tag := field.Tag
 311  	encoding := tag.Get("encoding")
 312  
 313  	if encoding == "binary" {
 314  		*binaryBodySpecified = true
 315  		return addBinaryBody(request, value, field)
 316  	}
 317  
 318  	rawJSON, e := json.Marshal(value.Interface())
 319  	if e != nil {
 320  		return
 321  	}
 322  	marshaled, e := removeNilFieldsInJSONWithTaggedStruct(rawJSON, value)
 323  	if e != nil {
 324  		return
 325  	}
 326  
 327  	if IsEnvVarTrue(EscapeJSONToASCIIEnvVar) {
 328  		marshaled, e = escapeJSONToASCII(marshaled)
 329  		if e != nil {
 330  			return
 331  		}
 332  	}
 333  
 334  	if defaultLogger.LogLevel() == verboseLogging {
 335  		Debugf("Marshaled body is: %s\n", string(marshaled))
 336  	}
 337  
 338  	bodyBytes := bytes.NewReader(marshaled)
 339  	request.ContentLength = int64(bodyBytes.Len())
 340  	request.Header.Set(requestHeaderContentLength, strconv.FormatInt(request.ContentLength, 10))
 341  	request.Header.Set(requestHeaderContentType, "application/json")
 342  	request.Body = ioutil.NopCloser(bodyBytes)
 343  	snapshot := *bodyBytes
 344  	request.GetBody = func() (io.ReadCloser, error) {
 345  		r := snapshot
 346  		return ioutil.NopCloser(&r), nil
 347  	}
 348  
 349  	return
 350  }
 351  
 352  func checkBinaryBodyLength(request *http.Request) (contentLen int64, err error) {
 353  	if isNopCloser(request.Body) {
 354  		ioReader := reflect.ValueOf(request.Body).Field(0).Interface().(io.Reader)
 355  		switch t := ioReader.(type) {
 356  		case *bytes.Reader:
 357  			return int64(t.Len()), nil
 358  		case *bytes.Buffer:
 359  			return int64(t.Len()), nil
 360  		case *strings.Reader:
 361  			return int64(t.Len()), nil
 362  		default:
 363  			return getNormalBinaryBodyLength(request)
 364  		}
 365  	}
 366  	if reflect.TypeOf(request.Body) == reflect.TypeOf((*os.File)(nil)) {
 367  		fi, err := (request.Body.(*os.File)).Stat()
 368  		if err != nil {
 369  			return contentLen, err
 370  		}
 371  		return fi.Size(), nil
 372  	}
 373  	return getNormalBinaryBodyLength(request)
 374  }
 375  
 376  // Helper function to judge if this struct is a nopCloser or nopCloserWriterTo
 377  func isNopCloser(readCloser io.ReadCloser) bool {
 378  	if reflect.TypeOf(readCloser) == reflect.TypeOf(io.NopCloser(nil)) || reflect.TypeOf(readCloser) == reflect.TypeOf(io.NopCloser(struct {
 379  		io.Reader
 380  		io.WriterTo
 381  	}{})) {
 382  		return true
 383  	}
 384  	return false
 385  }
 386  
 387  func getNormalBinaryBodyLength(request *http.Request) (contentLen int64, err error) {
 388  	// If binary body is seekable
 389  	seeker := getSeeker(request.Body)
 390  	if seeker != nil {
 391  		// save the current position, calculate the unread body length and seek it back to current position
 392  		if curPos, err := seeker.Seek(0, io.SeekCurrent); err == nil {
 393  			if endPos, err := seeker.Seek(0, io.SeekEnd); err == nil {
 394  				contentLen = endPos - curPos
 395  				if _, err = seeker.Seek(curPos, io.SeekStart); err == nil {
 396  					return contentLen, nil
 397  				}
 398  			}
 399  		}
 400  	}
 401  
 402  	var dumpRequestBody io.ReadCloser
 403  	if dumpRequestBody, request.Body, err = drainBody(request.Body); err != nil {
 404  		return contentLen, err
 405  	}
 406  	contentBody, err := ioutil.ReadAll(dumpRequestBody)
 407  	if err != nil {
 408  		return contentLen, err
 409  	}
 410  	return int64(len(contentBody)), nil
 411  }
 412  
 413  func getSeeker(readCloser io.ReadCloser) (seeker io.Seeker) {
 414  	if seeker, ok := readCloser.(io.Seeker); ok {
 415  		return seeker
 416  	}
 417  	// the binary body is wrapped with io.NopCloser
 418  	if isNopCloser(readCloser) {
 419  		if seeker, ok := reflect.ValueOf(readCloser).Field(0).Interface().(io.Seeker); ok {
 420  			return seeker
 421  		}
 422  	}
 423  	return seeker
 424  }
 425  
 426  func addToQuery(request *http.Request, value reflect.Value, field reflect.StructField) (e error) {
 427  	Debugln("Marshaling to query from field: ", field.Name)
 428  	if request.URL == nil {
 429  		request.URL = &url.URL{}
 430  	}
 431  	query := request.URL.Query()
 432  	var queryParameterValue, queryParameterName string
 433  
 434  	if queryParameterName = field.Tag.Get("name"); queryParameterName == "" {
 435  		return fmt.Errorf("marshaling request to a query requires the 'name' tag for field: %s ", field.Name)
 436  	}
 437  
 438  	mandatory, _ := strconv.ParseBool(strings.ToLower(field.Tag.Get("mandatory")))
 439  
 440  	//If mandatory and nil. Error out
 441  	if mandatory && isNil(value) {
 442  		return fmt.Errorf("marshaling request to a header requires not nil pointer for field: %s", field.Name)
 443  	}
 444  
 445  	//if not mandatory and nil. Omit
 446  	if !mandatory && isNil(value) {
 447  		Debugf("Query parameter value is not mandatory and is nil pointer in field: %s. Skipping query", field.Name)
 448  		return
 449  	}
 450  
 451  	encoding := strings.ToLower(field.Tag.Get("collectionFormat"))
 452  	var collectionFormatStringValues []string
 453  	switch encoding {
 454  	case "csv", "multi":
 455  		if value.Kind() != reflect.Slice && value.Kind() != reflect.Array {
 456  			e = fmt.Errorf("query parameter is tagged as csv or multi yet its type is neither an Array nor a Slice: %s", field.Name)
 457  			break
 458  		}
 459  
 460  		numOfElements := value.Len()
 461  		collectionFormatStringValues = make([]string, numOfElements)
 462  		for i := 0; i < numOfElements; i++ {
 463  			collectionFormatStringValues[i], e = toStringValue(value.Index(i), field)
 464  			if e != nil {
 465  				break
 466  			}
 467  		}
 468  		queryParameterValue = strings.Join(collectionFormatStringValues, ",")
 469  	case "":
 470  		queryParameterValue, e = toStringValue(value, field)
 471  	default:
 472  		e = fmt.Errorf("encoding of type %s is not supported for query param: %s", encoding, field.Name)
 473  	}
 474  
 475  	if e != nil {
 476  		return
 477  	}
 478  
 479  	//check for tag "omitEmpty", this is done to accomodate unset fields that do not
 480  	//support an empty string: enums in query params
 481  	if omitEmpty, present := field.Tag.Lookup("omitEmpty"); present {
 482  		omitEmptyBool, _ := strconv.ParseBool(strings.ToLower(omitEmpty))
 483  		if queryParameterValue != "" || !omitEmptyBool {
 484  			addToQueryForEncoding(&query, encoding, queryParameterName, queryParameterValue, collectionFormatStringValues)
 485  		} else {
 486  			Debugf("Omitting %s, is empty and omitEmpty tag is set", field.Name)
 487  		}
 488  	} else {
 489  		addToQueryForEncoding(&query, encoding, queryParameterName, queryParameterValue, collectionFormatStringValues)
 490  	}
 491  
 492  	request.URL.RawQuery = query.Encode()
 493  	return
 494  }
 495  
 496  func addToQueryForEncoding(query *url.Values, encoding string, queryParameterName string, queryParameterValue string, collectionFormatStringValues []string) {
 497  	if encoding == "multi" {
 498  		for _, stringValue := range collectionFormatStringValues {
 499  			query.Add(queryParameterName, stringValue)
 500  		}
 501  	} else {
 502  		query.Set(queryParameterName, queryParameterValue)
 503  	}
 504  }
 505  
 506  // Adds to the path of the url in the order they appear in the structure
 507  func addToPath(request *http.Request, value reflect.Value, field reflect.StructField) (e error) {
 508  	var additionalURLPathPart string
 509  	if additionalURLPathPart, e = toStringValue(value, field); e != nil {
 510  		return fmt.Errorf("can not marshal to path in request for field %s. Due to %s", field.Name, e.Error())
 511  	}
 512  
 513  	// path should not be empty for any operations
 514  	if len(additionalURLPathPart) == 0 {
 515  		return fmt.Errorf("value cannot be empty for field %s in path", field.Name)
 516  	}
 517  
 518  	// encode path param if EncodePathParamsEnvVar is set
 519  	if IsEnvVarTrue(EncodePathParamsEnvVar) {
 520  		additionalURLPathPart = url.PathEscape(additionalURLPathPart)
 521  	}
 522  
 523  	if request.URL == nil {
 524  		request.URL = &url.URL{}
 525  		request.URL.Path = ""
 526  	}
 527  	var currentURLPath = request.URL.Path
 528  
 529  	var templatedPathRegex, _ = regexp.Compile(".*{.+}.*")
 530  	if !templatedPathRegex.MatchString(currentURLPath) {
 531  		Debugln("Marshaling request to path by appending field:", field.Name)
 532  		allPath := []string{currentURLPath, additionalURLPathPart}
 533  		request.URL.Path = strings.Join(allPath, "/")
 534  	} else {
 535  		var fieldName string
 536  		if fieldName = field.Tag.Get("name"); fieldName == "" {
 537  			e = fmt.Errorf("marshaling request to path name and template requires a 'name' tag for field: %s", field.Name)
 538  			return
 539  		}
 540  		urlTemplate := currentURLPath
 541  		Debugln("Marshaling to path from field: ", field.Name, " in template: ", urlTemplate)
 542  		request.URL.Path = strings.Replace(urlTemplate, "{"+fieldName+"}", additionalURLPathPart, -1)
 543  	}
 544  	return
 545  }
 546  
 547  func setWellKnownHeaders(request *http.Request, headerName, headerValue string, contentLenSpecified *bool) (e error) {
 548  	switch strings.ToLower(headerName) {
 549  	case "content-length":
 550  		var len int
 551  		len, e = strconv.Atoi(headerValue)
 552  		if e != nil {
 553  			return
 554  		}
 555  		request.ContentLength = int64(len)
 556  		*contentLenSpecified = true
 557  	}
 558  	return nil
 559  }
 560  
 561  func addToHeader(request *http.Request, value reflect.Value, field reflect.StructField, contentLenSpecified *bool) (e error) {
 562  	Debugln("Marshaling to header from field: ", field.Name)
 563  	if request.Header == nil {
 564  		request.Header = http.Header{}
 565  	}
 566  
 567  	var headerName, headerValue string
 568  	if headerName = field.Tag.Get("name"); headerName == "" {
 569  		return fmt.Errorf("marshaling request to a header requires the 'name' tag for field: %s", field.Name)
 570  	}
 571  
 572  	mandatory, _ := strconv.ParseBool(strings.ToLower(field.Tag.Get("mandatory")))
 573  	//If mandatory and nil. Error out
 574  	if mandatory && isNil(value) {
 575  		return fmt.Errorf("marshaling request to a header requires not nil pointer for field: %s", field.Name)
 576  	}
 577  
 578  	// generate opc-request-id if header value is nil and header name matches
 579  	value = generateOpcRequestID(headerName, value)
 580  
 581  	//if not mandatory and nil. Omit
 582  	if !mandatory && isNil(value) {
 583  		Debugf("Header value is not mandatory and is nil pointer in field: %s. Skipping header", field.Name)
 584  		return
 585  	}
 586  
 587  	//Otherwise get value and set header
 588  	encoding := strings.ToLower(field.Tag.Get("collectionFormat"))
 589  	var collectionFormatStringValues []string
 590  	switch encoding {
 591  	case "csv", "multi":
 592  		if value.Kind() != reflect.Slice && value.Kind() != reflect.Array {
 593  			e = fmt.Errorf("header is tagged as csv or multi yet its type is neither an Array nor a Slice: %s", field.Name)
 594  			return
 595  		}
 596  
 597  		numOfElements := value.Len()
 598  		collectionFormatStringValues = make([]string, numOfElements)
 599  		for i := 0; i < numOfElements; i++ {
 600  			collectionFormatStringValues[i], e = toStringValue(value.Index(i), field)
 601  			if e != nil {
 602  				Debugf("Header element could not be marshalled to a string: %w", e)
 603  				return
 604  			}
 605  		}
 606  		headerValue = strings.Join(collectionFormatStringValues, ",")
 607  	default:
 608  		if headerValue, e = toStringValue(value, field); e != nil {
 609  			return
 610  		}
 611  	}
 612  
 613  	if e = setWellKnownHeaders(request, headerName, headerValue, contentLenSpecified); e != nil {
 614  		return
 615  	}
 616  
 617  	if isUniqueHeaderRequired(headerName) {
 618  		request.Header.Set(headerName, headerValue)
 619  	} else {
 620  		request.Header.Add(headerName, headerValue)
 621  	}
 622  	return
 623  }
 624  
 625  // Check if the header is required to be unique
 626  func isUniqueHeaderRequired(headerName string) bool {
 627  	return strings.EqualFold(headerName, requestHeaderContentType) || strings.EqualFold(headerName, requestHeaderContentLength)
 628  }
 629  
 630  // Header collection is a map of string to string that gets rendered as individual headers with a given prefix
 631  func addToHeaderCollection(request *http.Request, value reflect.Value, field reflect.StructField) (e error) {
 632  	Debugln("Marshaling to header-collection from field:", field.Name)
 633  	if request.Header == nil {
 634  		request.Header = http.Header{}
 635  	}
 636  
 637  	var headerPrefix string
 638  	if headerPrefix = field.Tag.Get("prefix"); headerPrefix == "" {
 639  		return fmt.Errorf("marshaling request to a header requires the 'prefix' tag for field: %s", field.Name)
 640  	}
 641  
 642  	mandatory, _ := strconv.ParseBool(strings.ToLower(field.Tag.Get("mandatory")))
 643  	//If mandatory and nil. Error out
 644  	if mandatory && isNil(value) {
 645  		return fmt.Errorf("marshaling request to a header requires not nil pointer for field: %s", field.Name)
 646  	}
 647  
 648  	//if not mandatory and nil. Omit
 649  	if !mandatory && isNil(value) {
 650  		Debugf("Header value is not mandatory and is nil pointer in field: %s. Skipping header", field.Name)
 651  		return
 652  	}
 653  
 654  	//cast to map
 655  	headerValues, ok := value.Interface().(map[string]string)
 656  	if !ok {
 657  		e = fmt.Errorf("header fields need to be of type map[string]string")
 658  		return
 659  	}
 660  
 661  	for k, v := range headerValues {
 662  		headerName := fmt.Sprintf("%s%s", headerPrefix, k)
 663  		request.Header.Set(headerName, v)
 664  	}
 665  	return
 666  }
 667  
 668  // Makes sure the incoming structure is able to be marshalled
 669  // to a request
 670  func checkForValidRequestStruct(s interface{}) (*reflect.Value, error) {
 671  	val := reflect.ValueOf(s)
 672  	for val.Kind() == reflect.Ptr {
 673  		if val.IsNil() {
 674  			return nil, fmt.Errorf("can not marshal to request a pointer to structure")
 675  		}
 676  		val = val.Elem()
 677  	}
 678  
 679  	if s == nil {
 680  		return nil, fmt.Errorf("can not marshal to request a nil structure")
 681  	}
 682  
 683  	if val.Kind() != reflect.Struct {
 684  		return nil, fmt.Errorf("can not marshal to request, expects struct input. Got %v", val.Kind())
 685  	}
 686  
 687  	return &val, nil
 688  }
 689  
 690  // Populates the parts of a request by reading tags in the passed structure
 691  // nested structs are followed recursively depth-first.
 692  func structToRequestPart(request *http.Request, val reflect.Value) (err error) {
 693  	typ := val.Type()
 694  	contentLenSpecified := false
 695  	binaryBodySpecified := false
 696  	for i := 0; i < typ.NumField(); i++ {
 697  		if err != nil {
 698  			return
 699  		}
 700  
 701  		sf := typ.Field(i)
 702  		//unexported
 703  		if sf.PkgPath != "" && !sf.Anonymous {
 704  			continue
 705  		}
 706  
 707  		sv := val.Field(i)
 708  		if method := sv.MethodByName("ValidateEnumValue"); reflect.Value.IsValid(method) {
 709  			if validateResult := method.Call([]reflect.Value{})[1].Interface(); validateResult != nil {
 710  				if err = validateResult.(error); err != nil {
 711  					return
 712  				}
 713  			}
 714  		}
 715  
 716  		tag := sf.Tag.Get("contributesTo")
 717  		switch tag {
 718  		case "header":
 719  			err = addToHeader(request, sv, sf, &contentLenSpecified)
 720  		case "header-collection":
 721  			err = addToHeaderCollection(request, sv, sf)
 722  		case "path":
 723  			err = addToPath(request, sv, sf)
 724  		case "query":
 725  			err = addToQuery(request, sv, sf)
 726  		case "body":
 727  			err = addToBody(request, sv, sf, &binaryBodySpecified)
 728  		case "":
 729  			Debugln(sf.Name, " does not contain contributes tag. Skipping.")
 730  		default:
 731  			err = fmt.Errorf("can not marshal field: %s. It needs to contain valid contributesTo tag", sf.Name)
 732  		}
 733  	}
 734  
 735  	// if content-length is not specified but with binary body, calculate the content length according to request body
 736  	if !contentLenSpecified && binaryBodySpecified && request.Body != nil && request.Body != http.NoBody {
 737  		contentLen, err := checkBinaryBodyLength(request)
 738  		if err == nil {
 739  			request.Header.Set(requestHeaderContentLength, strconv.FormatInt(contentLen, 10))
 740  			request.ContentLength = contentLen
 741  		}
 742  	}
 743  
 744  	//If content length is zero, to avoid sending transfer-coding: chunked header, need to explicitly set the body to nil/Nobody.
 745  	if request.Header != nil && request.Body != nil && request.Body != http.NoBody &&
 746  		parseContentLength(request.Header.Get(requestHeaderContentLength)) == 0 {
 747  		request.Body = http.NoBody
 748  	}
 749  	//If headers are and the content type was not set, we default to application/json
 750  	if request.Header != nil && request.Header.Get(requestHeaderContentType) == "" {
 751  		request.Header.Set(requestHeaderContentType, "application/json")
 752  	}
 753  
 754  	return
 755  }
 756  
 757  // HTTPRequestMarshaller marshals a structure to an http request using tag values in the struct
 758  // The marshaller tag should like the following
 759  //
 760  //	type A struct {
 761  //			 ANumber string `contributesTo="query" name="number"`
 762  //			 TheBody `contributesTo="body"`
 763  //	}
 764  //
 765  // where the contributesTo tag can be: header, path, query, body
 766  // and the 'name' tag is the name of the value used in the http request(not applicable for path)
 767  // If path is specified as part of the tag, the values are appened to the url path
 768  // in the order they appear in the structure
 769  // The current implementation only supports primitive types, except for the body tag, which needs a struct type.
 770  // The body of a request will be marshaled using the tags of the structure
 771  func HTTPRequestMarshaller(requestStruct interface{}, httpRequest *http.Request) (err error) {
 772  	var val *reflect.Value
 773  	if val, err = checkForValidRequestStruct(requestStruct); err != nil {
 774  		return
 775  	}
 776  
 777  	Debugln("Marshaling to Request: ", val.Type().Name())
 778  	err = structToRequestPart(httpRequest, *val)
 779  	return
 780  }
 781  
 782  // MakeDefaultHTTPRequest creates the basic http request with the necessary headers set
 783  func MakeDefaultHTTPRequest(method, path string) (httpRequest http.Request) {
 784  	httpRequest = http.Request{
 785  		Proto:      "HTTP/1.1",
 786  		ProtoMajor: 1,
 787  		ProtoMinor: 1,
 788  		Header:     make(http.Header),
 789  		URL:        &url.URL{},
 790  	}
 791  
 792  	httpRequest.Header.Set(requestHeaderContentLength, "0")
 793  	httpRequest.Header.Set(requestHeaderDate, time.Now().UTC().Format(http.TimeFormat))
 794  	httpRequest.Header.Set(requestHeaderOpcClientInfo, strings.Join([]string{defaultSDKMarker, Version()}, "/"))
 795  	httpRequest.Header.Set(requestHeaderAccept, "*/*")
 796  	httpRequest.Method = method
 797  	httpRequest.URL.Path = path
 798  	return
 799  }
 800  
 801  // MakeDefaultHTTPRequestWithTaggedStruct creates an http request from an struct with tagged fields, see HTTPRequestMarshaller
 802  // for more information
 803  func MakeDefaultHTTPRequestWithTaggedStruct(method, path string, requestStruct interface{}) (httpRequest http.Request, err error) {
 804  	httpRequest = MakeDefaultHTTPRequest(method, path)
 805  	err = HTTPRequestMarshaller(requestStruct, &httpRequest)
 806  	if err != nil {
 807  		return
 808  	}
 809  
 810  	return
 811  }
 812  
 813  // MakeDefaultHTTPRequestWithTaggedStructAndExtraHeaders creates an http request from an struct with tagged fields, see HTTPRequestMarshaller
 814  // for more information
 815  func MakeDefaultHTTPRequestWithTaggedStructAndExtraHeaders(method, path string, requestStruct interface{}, extraHeaders map[string]string) (httpRequest http.Request, err error) {
 816  	httpRequest, err = MakeDefaultHTTPRequestWithTaggedStruct(method, path, requestStruct)
 817  	for key, val := range extraHeaders {
 818  		httpRequest.Header.Set(key, val)
 819  	}
 820  	return
 821  }
 822  
 823  // UpdateRequestBinaryBody updates the http request's body once it is binary request and the request body is seekable
 824  // if the content length is zero, no need to update request body(since it's already been set to http.Nody)
 825  func UpdateRequestBinaryBody(httpRequest *http.Request, rsc *OCIReadSeekCloser) {
 826  	if parseContentLength(httpRequest.Header.Get(requestHeaderContentLength)) == 0 {
 827  		return
 828  	}
 829  	httpRequest.Body = rsc
 830  	return
 831  }
 832  
 833  ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 834  ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 835  //Request UnMarshaling
 836  ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 837  ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 838  
 839  // Makes sure the incoming structure is able to be unmarshaled
 840  // to a request
 841  func checkForValidResponseStruct(s interface{}) (*reflect.Value, error) {
 842  	val := reflect.ValueOf(s)
 843  	for val.Kind() == reflect.Ptr {
 844  		if val.IsNil() {
 845  			return nil, fmt.Errorf("can not unmarshal to response a pointer to nil structure")
 846  		}
 847  		val = val.Elem()
 848  	}
 849  
 850  	if s == nil {
 851  		return nil, fmt.Errorf("can not unmarshal to response a nil structure")
 852  	}
 853  
 854  	if val.Kind() != reflect.Struct {
 855  		return nil, fmt.Errorf("can not unmarshal to response, expects struct input. Got %v", val.Kind())
 856  	}
 857  
 858  	return &val, nil
 859  }
 860  
 861  func intSizeFromKind(kind reflect.Kind) int {
 862  	switch kind {
 863  	case reflect.Int8, reflect.Uint8:
 864  		return 8
 865  	case reflect.Int16, reflect.Uint16:
 866  		return 16
 867  	case reflect.Int32, reflect.Uint32:
 868  		return 32
 869  	case reflect.Int64, reflect.Uint64:
 870  		return 64
 871  	case reflect.Int, reflect.Uint:
 872  		return strconv.IntSize
 873  	default:
 874  		Debugf("The type is not valid: %v. Returing int size for arch\n", kind.String())
 875  		return strconv.IntSize
 876  	}
 877  
 878  }
 879  
 880  func analyzeValue(stringValue string, kind reflect.Kind, field reflect.StructField) (val reflect.Value, valPointer reflect.Value, err error) {
 881  	switch kind {
 882  	case timeType.Kind():
 883  		var t time.Time
 884  		t, err = tryParsingTimeWithValidFormatsForHeaders([]byte(stringValue), field.Name)
 885  		if err != nil {
 886  			return
 887  		}
 888  		sdkTime := sdkTimeFromTime(t)
 889  		val = reflect.ValueOf(sdkTime)
 890  		valPointer = reflect.ValueOf(&sdkTime)
 891  		return
 892  	case sdkDateType.Kind():
 893  		var t time.Time
 894  		t, err = tryParsingTimeWithValidFormatsForHeaders([]byte(stringValue), field.Name)
 895  		if err != nil {
 896  			return
 897  		}
 898  		sdkDate := sdkDateFromTime(t)
 899  		val = reflect.ValueOf(sdkDate)
 900  		valPointer = reflect.ValueOf(&sdkDate)
 901  		return
 902  	case reflect.Bool:
 903  		var bVal bool
 904  		if bVal, err = strconv.ParseBool(stringValue); err != nil {
 905  			return
 906  		}
 907  		val = reflect.ValueOf(bVal)
 908  		valPointer = reflect.ValueOf(&bVal)
 909  		return
 910  	case reflect.Int:
 911  		size := intSizeFromKind(kind)
 912  		var iVal int64
 913  		if iVal, err = strconv.ParseInt(stringValue, 10, size); err != nil {
 914  			return
 915  		}
 916  		var iiVal int
 917  		iiVal = int(iVal)
 918  		val = reflect.ValueOf(iiVal)
 919  		valPointer = reflect.ValueOf(&iiVal)
 920  		return
 921  	case reflect.Int64:
 922  		size := intSizeFromKind(kind)
 923  		var iVal int64
 924  		if iVal, err = strconv.ParseInt(stringValue, 10, size); err != nil {
 925  			return
 926  		}
 927  		val = reflect.ValueOf(iVal)
 928  		valPointer = reflect.ValueOf(&iVal)
 929  		return
 930  	case reflect.Uint:
 931  		size := intSizeFromKind(kind)
 932  		var iVal uint64
 933  		if iVal, err = strconv.ParseUint(stringValue, 10, size); err != nil {
 934  			return
 935  		}
 936  		var uiVal uint
 937  		uiVal = uint(iVal)
 938  		val = reflect.ValueOf(uiVal)
 939  		valPointer = reflect.ValueOf(&uiVal)
 940  		return
 941  	case reflect.String:
 942  		val = reflect.ValueOf(stringValue)
 943  		valPointer = reflect.ValueOf(&stringValue)
 944  	case reflect.Float32:
 945  		var fVal float64
 946  		if fVal, err = strconv.ParseFloat(stringValue, 32); err != nil {
 947  			return
 948  		}
 949  		var ffVal float32
 950  		ffVal = float32(fVal)
 951  		val = reflect.ValueOf(ffVal)
 952  		valPointer = reflect.ValueOf(&ffVal)
 953  		return
 954  	case reflect.Float64:
 955  		var fVal float64
 956  		if fVal, err = strconv.ParseFloat(stringValue, 64); err != nil {
 957  			return
 958  		}
 959  		val = reflect.ValueOf(fVal)
 960  		valPointer = reflect.ValueOf(&fVal)
 961  		return
 962  	default:
 963  		err = fmt.Errorf("value for kind: %s not supported", kind)
 964  	}
 965  	return
 966  }
 967  
 968  // Sets the field of a struct, with the appropriate value of the string
 969  // Only sets basic types
 970  func fromStringValue(newValue string, val *reflect.Value, field reflect.StructField) (err error) {
 971  
 972  	if !val.CanSet() {
 973  		err = fmt.Errorf("can not set field name: %s of type: %v", field.Name, val.Type().String())
 974  		return
 975  	}
 976  
 977  	kind := val.Kind()
 978  	isPointer := false
 979  	if val.Kind() == reflect.Ptr {
 980  		isPointer = true
 981  		kind = field.Type.Elem().Kind()
 982  	}
 983  
 984  	value, valPtr, err := analyzeValue(newValue, kind, field)
 985  	valueType := val.Type()
 986  	if err != nil {
 987  		return
 988  	}
 989  	if !isPointer {
 990  		val.Set(value.Convert(valueType))
 991  	} else {
 992  		val.Set(valPtr)
 993  	}
 994  	return
 995  }
 996  
 997  // PolymorphicJSONUnmarshaler is the interface to unmarshal polymorphic json payloads
 998  type PolymorphicJSONUnmarshaler interface {
 999  	UnmarshalPolymorphicJSON(data []byte) (interface{}, error)
1000  }
1001  
1002  func valueFromPolymorphicJSON(content []byte, unmarshaler PolymorphicJSONUnmarshaler) (val interface{}, err error) {
1003  	err = json.Unmarshal(content, unmarshaler)
1004  	if err != nil {
1005  		return
1006  	}
1007  	val, err = unmarshaler.UnmarshalPolymorphicJSON(content)
1008  	return
1009  }
1010  
1011  func valueFromJSONBody(response *http.Response, value *reflect.Value, unmarshaler PolymorphicJSONUnmarshaler) (val interface{}, err error) {
1012  	//Consumes the body, consider implementing it
1013  	//without body consumption
1014  	var content []byte
1015  	content, err = ioutil.ReadAll(response.Body)
1016  	if err != nil {
1017  		return
1018  	}
1019  
1020  	if unmarshaler != nil {
1021  		val, err = valueFromPolymorphicJSON(content, unmarshaler)
1022  		return
1023  	}
1024  
1025  	val = reflect.New(value.Type()).Interface()
1026  	err = json.Unmarshal(content, &val)
1027  	return
1028  }
1029  
1030  func addFromBody(response *http.Response, value *reflect.Value, field reflect.StructField, unmarshaler PolymorphicJSONUnmarshaler) (err error) {
1031  	Debugln("Unmarshalling from body to field: ", field.Name)
1032  	if response.Body == nil {
1033  		Debugln("Unmarshalling body skipped due to nil body content for field: ", field.Name)
1034  		return nil
1035  	}
1036  
1037  	tag := field.Tag
1038  	encoding := tag.Get("encoding")
1039  	var iVal interface{}
1040  	switch encoding {
1041  	case "binary":
1042  		value.Set(reflect.ValueOf(response.Body))
1043  		return
1044  	case "plain-text":
1045  		//Expects UTF-8
1046  		byteArr, e := ioutil.ReadAll(response.Body)
1047  		if e != nil {
1048  			return e
1049  		}
1050  		str := string(byteArr)
1051  		value.Set(reflect.ValueOf(&str))
1052  		return
1053  	default: //If the encoding is not set. we'll decode with json
1054  		iVal, err = valueFromJSONBody(response, value, unmarshaler)
1055  		if err != nil {
1056  			return
1057  		}
1058  
1059  		newVal := reflect.ValueOf(iVal)
1060  		if newVal.Kind() == reflect.Ptr {
1061  			newVal = newVal.Elem()
1062  		}
1063  		value.Set(newVal)
1064  		return
1065  	}
1066  }
1067  
1068  func addFromHeader(response *http.Response, value *reflect.Value, field reflect.StructField) (err error) {
1069  	Debugln("Unmarshaling from header to field: ", field.Name)
1070  	var headerName string
1071  	if headerName = field.Tag.Get("name"); headerName == "" {
1072  		return fmt.Errorf("unmarshaling response to a header requires the 'name' tag for field: %s", field.Name)
1073  	}
1074  
1075  	headerValue := response.Header.Get(headerName)
1076  	if headerValue == "" {
1077  		Debugf("Unmarshalling did not find header with name:%s", headerName)
1078  		return nil
1079  	}
1080  
1081  	if err = fromStringValue(headerValue, value, field); err != nil {
1082  		return fmt.Errorf("unmarshaling response to a header failed for field %s, due to %s", field.Name,
1083  			err.Error())
1084  	}
1085  	return
1086  }
1087  
1088  func addFromHeaderCollection(response *http.Response, value *reflect.Value, field reflect.StructField) error {
1089  	Debugln("Unmarshaling from header-collection to field:", field.Name)
1090  	var headerPrefix string
1091  	if headerPrefix = field.Tag.Get("prefix"); headerPrefix == "" {
1092  		return fmt.Errorf("unmarshaling response to a header-collection requires the 'prefix' tag for field: %s", field.Name)
1093  	}
1094  
1095  	mapCollection := make(map[string]string)
1096  	for name, value := range response.Header {
1097  		nameLowerCase := strings.ToLower(name)
1098  		if strings.HasPrefix(nameLowerCase, headerPrefix) {
1099  			headerNoPrefix := strings.TrimPrefix(nameLowerCase, headerPrefix)
1100  			mapCollection[headerNoPrefix] = value[0]
1101  		}
1102  	}
1103  
1104  	Debugln("Marshalled header collection is:", mapCollection)
1105  	value.Set(reflect.ValueOf(mapCollection))
1106  	return nil
1107  }
1108  
1109  // Populates a struct from parts of a request by reading tags of the struct
1110  func responseToStruct(response *http.Response, val *reflect.Value, unmarshaler PolymorphicJSONUnmarshaler) (err error) {
1111  	typ := val.Type()
1112  	for i := 0; i < typ.NumField(); i++ {
1113  		if err != nil {
1114  			return
1115  		}
1116  
1117  		sf := typ.Field(i)
1118  
1119  		//unexported
1120  		if sf.PkgPath != "" {
1121  			continue
1122  		}
1123  
1124  		sv := val.Field(i)
1125  		tag := sf.Tag.Get("presentIn")
1126  		switch tag {
1127  		case "header":
1128  			err = addFromHeader(response, &sv, sf)
1129  		case "header-collection":
1130  			err = addFromHeaderCollection(response, &sv, sf)
1131  		case "body":
1132  			err = addFromBody(response, &sv, sf, unmarshaler)
1133  		case "":
1134  			Debugln(sf.Name, " does not contain presentIn tag. Skipping")
1135  		default:
1136  			err = fmt.Errorf("can not unmarshal field: %s. It needs to contain valid presentIn tag", sf.Name)
1137  		}
1138  	}
1139  	return
1140  }
1141  
1142  // UnmarshalResponse hydrates the fields of a struct with the values of a http response, guided
1143  // by the field tags. The directive tag is "presentIn" and it can be either
1144  //   - "header": Will look for the header tagged as "name" in the headers of the struct and set it value to that
1145  //   - "body": It will try to marshal the body from a json string to a struct tagged with 'presentIn: "body"'.
1146  //
1147  // Further this method will consume the body it should be safe to close it after this function
1148  // Notice the current implementation only supports native types:int, strings, floats, bool as the field types
1149  func UnmarshalResponse(httpResponse *http.Response, responseStruct interface{}) (err error) {
1150  
1151  	// Check for text/event-stream content type, and return without unmarshalling
1152  	if httpResponse != nil && httpResponse.Header != nil && strings.ToLower(httpResponse.Header.Get("content-type")) == "text/event-stream" {
1153  		return
1154  	}
1155  
1156  	var val *reflect.Value
1157  	if val, err = checkForValidResponseStruct(responseStruct); err != nil {
1158  		return
1159  	}
1160  
1161  	if err = responseToStruct(httpResponse, val, nil); err != nil {
1162  		return
1163  	}
1164  
1165  	return nil
1166  }
1167  
1168  // UnmarshalResponseWithPolymorphicBody similar to UnmarshalResponse but assumes the body of the response
1169  // contains polymorphic json. This function will use the unmarshaler argument to unmarshal json content
1170  func UnmarshalResponseWithPolymorphicBody(httpResponse *http.Response, responseStruct interface{}, unmarshaler PolymorphicJSONUnmarshaler) (err error) {
1171  
1172  	var val *reflect.Value
1173  	if val, err = checkForValidResponseStruct(responseStruct); err != nil {
1174  		return
1175  	}
1176  
1177  	if err = responseToStruct(httpResponse, val, unmarshaler); err != nil {
1178  		return
1179  	}
1180  
1181  	return nil
1182  }
1183  
1184  // generate request id if user not provided and for each retry operation re-gen a new request id
1185  func generateOpcRequestID(headerName string, value reflect.Value) (newValue reflect.Value) {
1186  	newValue = value
1187  	isNilValue := isNil(newValue)
1188  	isOpcRequestIDHeader := headerName == requestHeaderOpcRequestID || headerName == requestHeaderOpcClientRequestID
1189  
1190  	if isNilValue && isOpcRequestIDHeader {
1191  		requestID, err := generateRandUUID()
1192  
1193  		if err != nil {
1194  			// this will not fail the request, just skip add opc-request-id
1195  			Debugf("unable to generate opc-request-id. %s", err.Error())
1196  		} else {
1197  			newValue = reflect.ValueOf(String(requestID))
1198  			Debugf("add request id for header: %s, with value: %s", headerName, requestID)
1199  		}
1200  	}
1201  
1202  	return
1203  }
1204