forked from ServiceStack/ServiceStack
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathRequestExtensions.cs
More file actions
306 lines (258 loc) · 11.3 KB
/
Copy pathRequestExtensions.cs
File metadata and controls
306 lines (258 loc) · 11.3 KB
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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
using System;
using System.IO;
using System.IO.Compression;
using System.Threading;
using System.Threading.Tasks;
using ServiceStack.Caching;
using ServiceStack.Configuration;
using ServiceStack.Host;
using ServiceStack.IO;
using ServiceStack.Text;
using ServiceStack.Web;
namespace ServiceStack
{
public static class RequestExtensions
{
public static AuthUserSession ReloadSession(this IRequest request)
{
return request.GetSession() as AuthUserSession;
}
public static string GetCompressionType(this IRequest request)
{
if (request.RequestPreferences.AcceptsDeflate)
return CompressionTypes.Deflate;
if (request.RequestPreferences.AcceptsGzip)
return CompressionTypes.GZip;
return null;
}
public static string GetContentEncoding(this IRequest request)
{
return request.Headers.Get(HttpHeaders.ContentEncoding);
}
public static Stream GetInputStream(this IRequest req, Stream stream)
{
var enc = req.GetContentEncoding();
if (enc == CompressionTypes.Deflate)
return new DeflateStream(stream, CompressionMode.Decompress);
if (enc == CompressionTypes.GZip)
return new GZipStream(stream, CompressionMode.Decompress);
return stream;
}
public static string GetHeader(this IRequest request, string headerName)
{
return request?.Headers.Get(headerName);
}
public static string GetParamInRequestHeader(this IRequest request, string name)
{
//Avoid reading request body for non x-www-form-urlencoded requests
return request.Headers[name]
?? request.QueryString[name]
?? (!HostContext.Config.SkipFormDataInCreatingRequest && request.ContentType.MatchesContentType(MimeTypes.FormUrlEncoded)
? request.FormData[name]
: null);
}
/// <summary>
/// Returns the optimized result for the IRequestContext.
/// Does not use or store results in any cache.
/// </summary>
/// <param name="request"></param>
/// <param name="dto"></param>
/// <returns></returns>
[Obsolete("Use ToOptimizedResultAsync")]
public static object ToOptimizedResult(this IRequest request, object dto)
{
var httpResult = dto as IHttpResult;
if (httpResult != null)
dto = httpResult.Response;
request.Response.Dto = dto;
var compressionType = request.GetCompressionType();
if (compressionType == null)
return HostContext.ContentTypes.SerializeToString(request, dto);
using (var ms = new MemoryStream())
using (var compressionStream = GetCompressionStream(ms, compressionType))
{
using (httpResult?.ResultScope?.Invoke())
{
using (var msBuffer = MemoryStreamFactory.GetStream())
{
HostContext.ContentTypes.SerializeToStreamAsync(request, dto, msBuffer).Wait();
msBuffer.Position = 0;
msBuffer.CopyTo(compressionStream);
}
compressionStream.Close();
}
var compressedBytes = ms.ToArray();
return new CompressedResult(compressedBytes, compressionType, request.ResponseContentType)
{
Status = request.Response.StatusCode
};
}
}
/// <summary>
/// Returns the optimized result for the IRequestContext.
/// Does not use or store results in any cache.
/// </summary>
public static async Task<object> ToOptimizedResultAsync(this IRequest request, object dto)
{
var httpResult = dto as IHttpResult;
if (httpResult != null)
dto = httpResult.Response;
request.Response.Dto = dto;
var compressionType = request.GetCompressionType();
if (compressionType == null)
return HostContext.ContentTypes.SerializeToString(request, dto);
using (var ms = new MemoryStream())
using (var compressionStream = GetCompressionStream(ms, compressionType))
{
using (httpResult?.ResultScope?.Invoke())
{
await HostContext.ContentTypes.SerializeToStreamAsync(request, dto, compressionStream);
compressionStream.Close();
}
var compressedBytes = ms.ToArray();
return new CompressedResult(compressedBytes, compressionType, request.ResponseContentType)
{
Status = request.Response.StatusCode
};
}
}
private static Stream GetCompressionStream(Stream outputStream, string compressionType)
{
if (compressionType == CompressionTypes.Deflate)
return StreamExt.DeflateProvider.DeflateStream(outputStream);
if (compressionType == CompressionTypes.GZip)
return StreamExt.GZipProvider.GZipStream(outputStream);
throw new NotSupportedException(compressionType);
}
/// <summary>
/// Overload for the <see cref="ContentCacheManager.Resolve"/> method returning the most
/// optimized result based on the MimeType and CompressionType from the IRequestContext.
/// </summary>
public static object ToOptimizedResultUsingCache<T>(
this IRequest requestContext, ICacheClient cacheClient, string cacheKey,
Func<T> factoryFn)
{
return requestContext.ToOptimizedResultUsingCache(cacheClient, cacheKey, null, factoryFn);
}
/// <summary>
/// Overload for the <see cref="ContentCacheManager.Resolve"/> method returning the most
/// optimized result based on the MimeType and CompressionType from the IRequestContext.
/// <param name="expireCacheIn">How long to cache for, null is no expiration</param>
/// </summary>
public static object ToOptimizedResultUsingCache<T>(
this IRequest requestContext, ICacheClient cacheClient, string cacheKey,
TimeSpan? expireCacheIn, Func<T> factoryFn)
{
var cacheResult = cacheClient.ResolveFromCache(cacheKey, requestContext);
if (cacheResult != null)
return cacheResult;
cacheResult = cacheClient.Cache(cacheKey, factoryFn(), requestContext, expireCacheIn);
return cacheResult;
}
/// <summary>
/// Clears all the serialized and compressed caches set
/// by the 'Resolve' method for the cacheKey provided
/// </summary>
/// <param name="requestContext"></param>
/// <param name="cacheClient"></param>
/// <param name="cacheKeys"></param>
public static void RemoveFromCache(
this IRequest requestContext, ICacheClient cacheClient, params string[] cacheKeys)
{
cacheClient.ClearCaches(cacheKeys);
}
/// <summary>
/// Store an entry in the IHttpRequest.Items Dictionary
/// </summary>
public static void SetItem(this IRequest httpReq, string key, object value)
{
if (httpReq == null) return;
httpReq.Items[key] = value;
}
/// <summary>
/// Get an entry from the IHttpRequest.Items Dictionary
/// </summary>
public static object GetItem(this IRequest httpReq, string key)
{
if (httpReq == null) return null;
httpReq.Items.TryGetValue(key, out var value);
return value;
}
#if !NETSTANDARD2_0
public static RequestBaseWrapper ToHttpRequestBase(this IRequest httpReq)
{
return new RequestBaseWrapper((IHttpRequest)httpReq);
}
#endif
public static void SetInProcessRequest(this IRequest httpReq)
{
if (httpReq == null) return;
httpReq.RequestAttributes |= RequestAttributes.InProcess;
}
public static bool IsInProcessRequest(this IRequest httpReq)
{
return (RequestAttributes.InProcess & httpReq?.RequestAttributes) == RequestAttributes.InProcess;
}
public static void ReleaseIfInProcessRequest(this IRequest httpReq)
{
if (httpReq == null) return;
httpReq.RequestAttributes = httpReq.RequestAttributes & ~RequestAttributes.InProcess;
}
internal static T TryResolveInternal<T>(this IRequest request)
{
if (typeof(T) == typeof(IRequest))
return (T)request;
if (typeof(T) == typeof(IResponse))
return (T)request.Response;
return request is IHasResolver hasResolver
? hasResolver.Resolver.TryResolve<T>()
: Service.GlobalResolver.TryResolve<T>();
}
public static IVirtualFile GetFile(this IRequest request) => request is IHasVirtualFiles vfs ? vfs.GetFile() : null;
public static IVirtualDirectory GetDirectory(this IRequest request) => request is IHasVirtualFiles vfs ? vfs.GetDirectory() : null;
public static bool IsFile(this IRequest request) => request is IHasVirtualFiles vfs && vfs.IsFile;
public static bool IsDirectory(this IRequest request) => request is IHasVirtualFiles vfs && vfs.IsDirectory;
public static T GetRuntimeConfig<T>(this IRequest req, string name, T defaultValue)
{
return req != null
? HostContext.AppHost.GetRuntimeConfig(req, name, defaultValue)
: defaultValue;
}
}
// Share same buffered impl/behavior across all Hosts
internal static class BufferedExtensions
{
internal static MemoryStream CreateBufferedStream(this IResponse response)
{
return MemoryStreamFactory.GetStream();
}
internal static MemoryStream CreateBufferedStream(this Stream stream)
{
return stream.CopyToNewMemoryStream();
}
internal static string ReadBufferedStreamToEnd(this MemoryStream stream)
{
return stream.ReadToEnd();
}
internal static void FlushBufferIfAny(this IResponse response, MemoryStream buffer, Stream output)
{
if (buffer == null)
return;
try {
response.SetContentLength(buffer.Length); //safe to set Length in Buffered Response
} catch {}
buffer.WriteTo(output);
buffer.SetLength(buffer.Position = 0); //reset
}
internal static async Task FlushBufferIfAnyAsync(this IResponse response, MemoryStream buffer, Stream output, CancellationToken token=default(CancellationToken))
{
if (buffer == null)
return;
try {
response.SetContentLength(buffer.Length); //safe to set Length in Buffered Response
} catch {}
await buffer.WriteToAsync(output, token: token);
buffer.SetLength(buffer.Position = 0); //reset
}
}
}