Skip to content

Commit

Permalink
Fix #17740 (multipart/form-data request) and proxy behaviour (#18315)
Browse files Browse the repository at this point in the history
* Support multipart requests

* Further code optimization

* Update ApiClient.ps1

* Set $Multipart

* Corrections after petstore tests

* Update api_client.mustache

* Update api_client.nustache

* Update api_client.mustache

* Tabs removed
  • Loading branch information
condorcorde authored Apr 7, 2024
1 parent 650e119 commit fbc8616
Show file tree
Hide file tree
Showing 3 changed files with 156 additions and 219 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,10 @@ function Invoke-{{{apiNamePrefix}}}ApiClient {
$Configuration = Get-{{{apiNamePrefix}}}Configuration
$RequestUri = $Configuration["BaseUrl"] + $Uri
$DefaultHeaders = $Configuration["DefaultHeaders"]
# should make sure that SkipCertificateCheck is not set for PowerShell 5
$SkipCertificateCheck = $Configuration["SkipCertificateCheck"]
$Proxy = $Configuration["Proxy"]

# cookie parameters
foreach ($Parameter in $CookieParameters.GetEnumerator()) {
Expand All @@ -56,19 +59,17 @@ function Invoke-{{{apiNamePrefix}}}ApiClient {
$HeaderParameters['Accept'] = $Accept
}

[string]$MultiPartBoundary = $null
$ContentType= SelectHeaders -Headers $ContentTypes
# Content-Type and multipart handling
$ContentType = SelectHeaders -Headers $ContentTypes
if ($ContentType) {
$HeaderParameters['Content-Type'] = $ContentType
if ($ContentType -eq 'multipart/form-data') {
[string]$MultiPartBoundary = [System.Guid]::NewGuid()
$MultiPartBoundary = "---------------------------$MultiPartBoundary"
$HeaderParameters['Content-Type'] = "$ContentType; boundary=$MultiPartBoundary"
$MultiPart = $true
}
}

# add default headers if any
foreach ($header in $Configuration["DefaultHeaders"].GetEnumerator()) {
foreach ($header in $DefaultHeaders.GetEnumerator()) {
$HeaderParameters[$header.Name] = $header.Value
}

Expand All @@ -89,30 +90,7 @@ function Invoke-{{{apiNamePrefix}}}ApiClient {

# include form parameters in the request body
if ($FormParameters -and $FormParameters.Count -gt 0) {
if (![string]::IsNullOrEmpty($MultiPartBoundary)) {
$RequestBody = ""
$LF = "`r`n"
$FormParameters.Keys | ForEach-Object {
$value = $FormParameters[$_]
$isFile = $value.GetType().FullName -eq "System.IO.FileInfo"
$RequestBody += "--$MultiPartBoundary$LF"
$RequestBody += "Content-Disposition: form-data; name=`"$_`""
if ($isFile) {
$fileName = $value.Name
$RequestBody += "; filename=`"$fileName`"$LF"
$RequestBody += "Content-Type: application/octet-stream$LF$LF"
$RequestBody += Get-Content -Path $value.FullName
} else {
$RequestBody += "$LF$LF"
$RequestBody += ([string]$value)
}
$RequestBody += "$LF--$MultiPartBoundary"
}
$RequestBody += "--"
} else {
$RequestBody = $FormParameters
}
$RequestBody = $FormParameters
}

if ($Body -or $IsBodyNullable) {
Expand Down Expand Up @@ -141,54 +119,55 @@ function Invoke-{{{apiNamePrefix}}}ApiClient {
}

{{/hasHttpSignatureMethods}}
# use splatting to pass parameters
$Params = @{}
$Params.Uri = $UriBuilder.Uri
$Params.Method = $Method
$Params.Headers = $HeaderParameters
$Params.ErrorAction = 'Stop'

if ($SkipCertificateCheck -eq $true) {
if ($null -eq $Configuration["Proxy"]) {
# skip certification check, no proxy
$Response = Invoke-WebRequest -Uri $UriBuilder.Uri `
-Method $Method `
-Headers $HeaderParameters `
-Body $RequestBody `
-ErrorAction Stop `
-UseBasicParsing `
-SkipCertificateCheck
} else {
# skip certification check, use proxy
$Response = Invoke-WebRequest -Uri $UriBuilder.Uri `
-Method $Method `
-Headers $HeaderParameters `
-Body $RequestBody `
-ErrorAction Stop `
-UseBasicParsing `
-SkipCertificateCheck `
-Proxy $Configuration["Proxy"].GetProxy($UriBuilder.Uri) `
-ProxyUseDefaultCredentials
$Params.SkipCertificateCheck = $true
}

if ($null -ne $Proxy) {
$effectiveProxy = $Proxy.GetProxy($UriBuilder.Uri)
# do not set proxy if it is null or same as target Uri
if ($null -ne $effectiveProxy -and $effectiveProxy.AbsoluteUri -ne $UriBuilder.Uri) {
$Params.Proxy = $effectiveProxy.AbsoluteUri
$Params.ProxyUseDefaultCredentials = $true
}
} else {
if ($null -eq $Configuration["Proxy"]) {
# perform certification check, no proxy
$Response = Invoke-WebRequest -Uri $UriBuilder.Uri `
-Method $Method `
-Headers $HeaderParameters `
-Body $RequestBody `
-ErrorAction Stop `
-UseBasicParsing
}

# use Invoke-RestApi if Content-Type is 'multipart/form-data', Invoke-WebRequest otherwise
if ($MultiPart) {
if ($PSVersionTable.PSVersion.Major -eq 5) {
# preset null return values as not supported by Invoke-RestMethod on PS5
$ResponseHeaders = $null
$ResponseStatusCode = $null
} else {
# perform certification check, use proxy
$Response = Invoke-WebRequest -Uri $UriBuilder.Uri `
-Method $Method `
-Headers $HeaderParameters `
-Body $RequestBody `
-ErrorAction Stop `
-UseBasicParsing `
-Proxy $Configuration["Proxy"].GetProxy($UriBuilder.Uri) `
-ProxyUseDefaultCredentials
# preset return variables
$Params.ResponseHeadersVariable = "ResponseHeaders"
$Params.StatusCodeVariable = "ResponseStatusCode"
}
}
$Params.Form = $FormParameters
$Response = Invoke-RestMethod @Params

return @{
Response = $Response
StatusCode = $ResponseStatusCode
Headers = $ResponseHeaders
}
} else {
$Params.Body = $RequestBody
$Params.UseBasicParsing = $true
$Response = Invoke-WebRequest @Params
return @{
Response = DeserializeResponse -Response $Response.Content -ReturnType $ReturnType -ContentTypes $Response.Headers["Content-Type"]
StatusCode = $Response.StatusCode
Headers = $Response.Headers
return @{
Response = DeserializeResponse -Response $Response.Content -ReturnType $ReturnType -ContentTypes $Response.Headers["Content-Type"]
StatusCode = $Response.StatusCode
Headers = $Response.Headers
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,10 @@ function Invoke-ApiClient {

$Configuration = Get-Configuration
$RequestUri = $Configuration["BaseUrl"] + $Uri
$DefaultHeaders = $Configuration["DefaultHeaders"]
# should make sure that SkipCertificateCheck is not set for PowerShell 5
$SkipCertificateCheck = $Configuration["SkipCertificateCheck"]
$Proxy = $Configuration["Proxy"]

# cookie parameters
foreach ($Parameter in $CookieParameters.GetEnumerator()) {
Expand All @@ -63,19 +66,17 @@ function Invoke-ApiClient {
$HeaderParameters['Accept'] = $Accept
}

[string]$MultiPartBoundary = $null
$ContentType= SelectHeaders -Headers $ContentTypes
# Content-Type and multipart handling
$ContentType = SelectHeaders -Headers $ContentTypes
if ($ContentType) {
$HeaderParameters['Content-Type'] = $ContentType
if ($ContentType -eq 'multipart/form-data') {
[string]$MultiPartBoundary = [System.Guid]::NewGuid()
$MultiPartBoundary = "---------------------------$MultiPartBoundary"
$HeaderParameters['Content-Type'] = "$ContentType; boundary=$MultiPartBoundary"
$MultiPart = $true
}
}

# add default headers if any
foreach ($header in $Configuration["DefaultHeaders"].GetEnumerator()) {
foreach ($header in $DefaultHeaders.GetEnumerator()) {
$HeaderParameters[$header.Name] = $header.Value
}

Expand All @@ -96,30 +97,7 @@ function Invoke-ApiClient {

# include form parameters in the request body
if ($FormParameters -and $FormParameters.Count -gt 0) {
if (![string]::IsNullOrEmpty($MultiPartBoundary)) {
$RequestBody = ""
$LF = "`r`n"
$FormParameters.Keys | ForEach-Object {
$value = $FormParameters[$_]
$isFile = $value.GetType().FullName -eq "System.IO.FileInfo"

$RequestBody += "--$MultiPartBoundary$LF"
$RequestBody += "Content-Disposition: form-data; name=`"$_`""
if ($isFile) {
$fileName = $value.Name
$RequestBody += "; filename=`"$fileName`"$LF"
$RequestBody += "Content-Type: application/octet-stream$LF$LF"
$RequestBody += Get-Content -Path $value.FullName
} else {
$RequestBody += "$LF$LF"
$RequestBody += ([string]$value)
}
$RequestBody += "$LF--$MultiPartBoundary"
}
$RequestBody += "--"
} else {
$RequestBody = $FormParameters
}
$RequestBody = $FormParameters
}

if ($Body -or $IsBodyNullable) {
Expand All @@ -129,54 +107,55 @@ function Invoke-ApiClient {
}
}

# use splatting to pass parameters
$Params = @{}
$Params.Uri = $UriBuilder.Uri
$Params.Method = $Method
$Params.Headers = $HeaderParameters
$Params.ErrorAction = 'Stop'

if ($SkipCertificateCheck -eq $true) {
if ($null -eq $Configuration["Proxy"]) {
# skip certification check, no proxy
$Response = Invoke-WebRequest -Uri $UriBuilder.Uri `
-Method $Method `
-Headers $HeaderParameters `
-Body $RequestBody `
-ErrorAction Stop `
-UseBasicParsing `
-SkipCertificateCheck
} else {
# skip certification check, use proxy
$Response = Invoke-WebRequest -Uri $UriBuilder.Uri `
-Method $Method `
-Headers $HeaderParameters `
-Body $RequestBody `
-ErrorAction Stop `
-UseBasicParsing `
-SkipCertificateCheck `
-Proxy $Configuration["Proxy"].GetProxy($UriBuilder.Uri) `
-ProxyUseDefaultCredentials
$Params.SkipCertificateCheck = $true
}

if ($null -ne $Proxy) {
$effectiveProxy = $Proxy.GetProxy($UriBuilder.Uri)
# do not set proxy if it is null or same as target Uri
if ($null -ne $effectiveProxy -and $effectiveProxy.AbsoluteUri -ne $UriBuilder.Uri) {
$Params.Proxy = $effectiveProxy.AbsoluteUri
$Params.ProxyUseDefaultCredentials = $true
}
} else {
if ($null -eq $Configuration["Proxy"]) {
# perform certification check, no proxy
$Response = Invoke-WebRequest -Uri $UriBuilder.Uri `
-Method $Method `
-Headers $HeaderParameters `
-Body $RequestBody `
-ErrorAction Stop `
-UseBasicParsing
}

# use Invoke-RestApi if Content-Type is 'multipart/form-data', Invoke-WebRequest otherwise
if ($MultiPart) {
if ($PSVersionTable.PSVersion.Major -eq 5) {
# preset null return values as not supported by Invoke-RestMethod on PS5
$ResponseHeaders = $null
$ResponseStatusCode = $null
} else {
# perform certification check, use proxy
$Response = Invoke-WebRequest -Uri $UriBuilder.Uri `
-Method $Method `
-Headers $HeaderParameters `
-Body $RequestBody `
-ErrorAction Stop `
-UseBasicParsing `
-Proxy $Configuration["Proxy"].GetProxy($UriBuilder.Uri) `
-ProxyUseDefaultCredentials
# preset return variables
$Params.ResponseHeadersVariable = "ResponseHeaders"
$Params.StatusCodeVariable = "ResponseStatusCode"
}
}
$Params.Form = $FormParameters
$Response = Invoke-RestMethod @Params

return @{
Response = $Response
StatusCode = $ResponseStatusCode
Headers = $ResponseHeaders
}
} else {
$Params.Body = $RequestBody
$Params.UseBasicParsing = $true
$Response = Invoke-WebRequest @Params

return @{
Response = DeserializeResponse -Response $Response.Content -ReturnType $ReturnType -ContentTypes $Response.Headers["Content-Type"]
StatusCode = $Response.StatusCode
Headers = $Response.Headers
return @{
Response = DeserializeResponse -Response $Response.Content -ReturnType $ReturnType -ContentTypes $Response.Headers["Content-Type"]
StatusCode = $Response.StatusCode
Headers = $Response.Headers
}
}
}

Expand Down
Loading

0 comments on commit fbc8616

Please sign in to comment.