/
ProxyExtensions.cs
152 lines (132 loc) · 5.56 KB
/
ProxyExtensions.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Primitives;
namespace Proxy
{
internal static class ProxyAdvancedExtensions
{
private const int StreamCopyBufferSize = 81920;
public static HttpRequestMessage CreateProxyHttpRequest(this HttpContext context, Uri uri)
{
var request = context.Request;
var proxiedMessage = new HttpRequestMessage();
var hasContent = SetupMethodAndContent(request, proxiedMessage);
// Copy the request headers
foreach (var header in request.Headers)
{
var headerValue = header.Value;
if (headerValue.Count == 1)
{
var value = headerValue.ToString();
if (!proxiedMessage.Headers.TryAddWithoutValidation(header.Key, value) && hasContent)
{
proxiedMessage.Content.Headers.TryAddWithoutValidation(header.Key, value);
}
}
else
{
var value = headerValue.ToArray();
if (!proxiedMessage.Headers.TryAddWithoutValidation(header.Key, value) && hasContent)
{
proxiedMessage.Content.Headers.TryAddWithoutValidation(header.Key, value);
}
}
}
proxiedMessage.Headers.Host = uri.Authority;
proxiedMessage.RequestUri = uri;
return proxiedMessage;
static bool SetupMethodAndContent(HttpRequest request, HttpRequestMessage proxiedMessage)
{
var hasContent = false;
var requestMethod = request.Method;
// Try to use the static HttpMethods rather than creating a new one.
if (HttpMethods.IsGet(requestMethod))
{
proxiedMessage.Method = HttpMethod.Get;
}
else if (HttpMethods.IsHead(requestMethod))
{
proxiedMessage.Method = HttpMethod.Head;
}
else if (HttpMethods.IsDelete(requestMethod))
{
proxiedMessage.Method = HttpMethod.Delete;
}
else if (HttpMethods.IsTrace(requestMethod))
{
proxiedMessage.Method = HttpMethod.Trace;
}
else
{
hasContent = true;
if (HttpMethods.IsPost(requestMethod))
{
proxiedMessage.Method = HttpMethod.Post;
}
else if (HttpMethods.IsOptions(requestMethod))
{
proxiedMessage.Method = HttpMethod.Options;
}
else if (HttpMethods.IsPut(requestMethod))
{
proxiedMessage.Method = HttpMethod.Put;
}
else if (HttpMethods.IsPatch(requestMethod))
{
proxiedMessage.Method = HttpMethod.Patch;
}
else
{
proxiedMessage.Method = new HttpMethod(request.Method);
}
proxiedMessage.Content = new StreamContent(request.Body);
}
return hasContent;
}
}
public static async Task CopyProxyHttpResponse(this HttpContext context, HttpResponseMessage replyMessage)
{
if (replyMessage == null)
{
throw new ArgumentNullException(nameof(replyMessage));
}
var response = context.Response;
response.StatusCode = (int)replyMessage.StatusCode;
var responseHeaders = response.Headers;
CopyHeaders(responseHeaders, replyMessage.Headers);
CopyHeaders(responseHeaders, replyMessage.Content.Headers);
// SendAsync removes chunking from the response. This removes the header so it doesn't expect a chunked response.
responseHeaders.Remove("transfer-encoding");
using (var responseStream = await replyMessage.Content.ReadAsStreamAsync())
{
await responseStream.CopyToAsync(response.Body, StreamCopyBufferSize, context.RequestAborted);
}
static void CopyHeaders(IHeaderDictionary responseHeaders, IEnumerable<KeyValuePair<string, IEnumerable<string>>> replyHeaders)
{
foreach (var replyHeader in replyHeaders)
{
var headerValue = default(StringValues);
var isFirst = true;
foreach (var value in replyHeader.Value)
{
if (isFirst)
{
headerValue = value;
isFirst = false;
}
else
{
headerValue = StringValues.Concat(headerValue, value);
}
}
responseHeaders[replyHeader.Key] = headerValue;
}
}
}
}
}