@DarrelMiller のソリューションを使用しましたが、機能します。ただし、いくつかの改善を行いました
私はコードをリファクタリングしたので、すべてが引数としてCopyRequest
取られるようになりました。response
var newRequest = CopyRequest(response);
base.SendAsync(newRequest, cancellationToken)
.ContinueWith(t2 => tcs.SetResult(t2.Result));
これは私が改善した CopyRequest メソッドです
- 新しいコンテンツを作成し
StreamContent
て null に設定する代わりにRedirect / Found / SeeOther
、コンテンツは必要な場合にのみ設定されます。
- RequestUri は、Location が設定されている場合にのみ設定され、相対 URI ではない可能性があることを考慮します。
- 最も重要なこと: 新しい Uri を確認し、ホストが一致しない場合は、認証情報が外部ホストに漏洩するのを防ぐために、認証ヘッダーをコピーしません。
private static HttpRequestMessage CopyRequest(HttpResponseMessage response)
{
var oldRequest = response.RequestMessage;
var newRequest = new HttpRequestMessage(oldRequest.Method, oldRequest.RequestUri);
if (response.Headers.Location != null)
{
if (response.Headers.Location.IsAbsoluteUri)
{
newRequest.RequestUri = response.Headers.Location;
}
else
{
newRequest.RequestUri = new Uri(newRequest.RequestUri, response.Headers.Location);
}
}
foreach (var header in oldRequest.Headers)
{
if (header.Key.Equals("Authorization", StringComparison.OrdinalIgnoreCase) && !(oldRequest.RequestUri.Host.Equals(newRequest.RequestUri.Host)))
{
//do not leak Authorization Header to other hosts
continue;
}
newRequest.Headers.TryAddWithoutValidation(header.Key, header.Value);
}
foreach (var property in oldRequest.Properties)
{
newRequest.Properties.Add(property);
}
if (response.StatusCode == HttpStatusCode.Redirect
|| response.StatusCode == HttpStatusCode.Found
|| response.StatusCode == HttpStatusCode.SeeOther)
{
newRequest.Content = null;
newRequest.Method = HttpMethod.Get;
}
else if (oldRequest.Content != null)
{
newRequest.Content = new StreamContent(oldRequest.Content.ReadAsStreamAsync().Result);
}
return newRequest;
}