Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

fixed the issue w/ handling requests that have no body

  • Loading branch information...
commit 5cb4aa4c37a1e4fee8bde69cdb4147d1a0029d92 1 parent 9cab560
Jeremy D. Miller jeremydmiller authored
21 src/FubuMVC.OwinHost/EnvironmentExtensions.cs
... ... @@ -0,0 +1,21 @@
  1 +using Gate;
  2 +
  3 +namespace FubuMVC.OwinHost
  4 +{
  5 + public static class EnvironmentExtensions
  6 + {
  7 + public static string ContentType(this Environment environment)
  8 + {
  9 + string value;
  10 + return (environment.Headers != null && environment.Headers.TryGetValue("Content-Type", out value))
  11 + ? value
  12 + : null;
  13 + }
  14 +
  15 + public static T Get<T>(this Environment environment, string name)
  16 + {
  17 + object value;
  18 + return environment.TryGetValue(name, out value) ? (T)value : default(T);
  19 + }
  20 + }
  21 +}
53 src/FubuMVC.OwinHost/FormRequestReader.cs
... ... @@ -0,0 +1,53 @@
  1 +using System;
  2 +using System.Collections.Generic;
  3 +using System.Linq;
  4 +using System.Text;
  5 +
  6 +namespace FubuMVC.OwinHost
  7 +{
  8 + public class FormRequestReader : IOwinRequestReader
  9 + {
  10 + private readonly Action<IDictionary<string, string>> _finish;
  11 + private readonly StringBuilder _builder;
  12 + private readonly Encoding _encoding;
  13 +
  14 + public FormRequestReader(Action<IDictionary<string, string>> finish)
  15 + {
  16 + _finish = finish;
  17 + _builder = new StringBuilder();
  18 + _encoding = Encoding.UTF8; // TODO -- is this a good idea?
  19 + }
  20 +
  21 + public void Read(byte[] bytes, int offset, int count)
  22 + {
  23 + var text = _encoding.GetString(bytes, offset, count);
  24 + _builder.Append(text);
  25 + }
  26 +
  27 + public IDictionary<string, string> PostData()
  28 + {
  29 + return Parse(_builder.ToString());
  30 + }
  31 +
  32 + public static IDictionary<string, string> Parse(string queryString)
  33 + {
  34 + // TODO: this is wrong in many, many ways
  35 + return (queryString ?? "").Split("&".ToCharArray())
  36 + .Select(item => item.Split("=".ToCharArray(), 2))
  37 + .Where(item => item.Length == 2)
  38 + .GroupBy(item => item[0], item => Decode(item[1]), StringComparer.OrdinalIgnoreCase)
  39 + .ToDictionary(g => g.Key, g => string.Join(",", g.ToArray()), StringComparer.OrdinalIgnoreCase);
  40 +
  41 + }
  42 +
  43 + static string Decode(string value)
  44 + {
  45 + return value.Replace("%3A", ":").Replace("%2F", "/");
  46 + }
  47 +
  48 + public void Finish()
  49 + {
  50 + _finish(PostData());
  51 + }
  52 + }
  53 +}
5 src/FubuMVC.OwinHost/FubuMVC.OwinHost.csproj
@@ -55,14 +55,19 @@
55 55 <Compile Include="..\CommonAssemblyInfo.cs">
56 56 <Link>CommonAssemblyInfo.cs</Link>
57 57 </Compile>
  58 + <Compile Include="EnvironmentExtensions.cs" />
  59 + <Compile Include="FormRequestReader.cs" />
58 60 <Compile Include="FubuOwinHost.cs" />
  61 + <Compile Include="IOwinRequestReader.cs" />
59 62 <Compile Include="OwinAggregateDictionary.cs" />
60 63 <Compile Include="GateHttpContext.cs" />
61 64 <Compile Include="OwinCurrentHttpRequest.cs" />
62 65 <Compile Include="OwinHttpWriter.cs" />
  66 + <Compile Include="OwinRequestBody.cs" />
63 67 <Compile Include="OwinServiceArguments.cs" />
64 68 <Compile Include="OwinStreamingData.cs" />
65 69 <Compile Include="Properties\AssemblyInfo.cs" />
  70 + <Compile Include="StreamDataReader.cs" />
66 71 </ItemGroup>
67 72 <ItemGroup>
68 73 <None Include="packages.config" />
119 src/FubuMVC.OwinHost/FubuOwinHost.cs
@@ -18,13 +18,12 @@ namespace FubuMVC.OwinHost
18 18 Action<Exception>, //error
19 19 Action, //complete
20 20 Action>; //cancel
21   -
22   - using BodyDelegate = System.Func<System.Func<System.ArraySegment<byte>, // data
23   - System.Action, // continuation
24   - bool>, // continuation will be invoked
25   - System.Action<System.Exception>, // onError
26   - System.Action, // on Complete
27   - System.Action>; // cancel
  21 + using BodyDelegate = Func<Func<ArraySegment<byte>, // data
  22 + Action, // continuation
  23 + bool>, // continuation will be invoked
  24 + Action<Exception>, // onError
  25 + Action, // on Complete
  26 + Action>; // cancel
28 27
29 28 public class FubuOwinHost
30 29 {
@@ -36,9 +35,6 @@ public void ExecuteRequest(IDictionary<string, object> env, ResultDelegate resul
36 35 var response = new Response(result);
37 36
38 37
39   -
40   -
41   -
42 38 if (Verbose) Console.WriteLine("Received {0} - {1}", environment.Method, environment.Path);
43 39
44 40 var routeData = determineRouteData(environment);
@@ -49,34 +45,43 @@ public void ExecuteRequest(IDictionary<string, object> env, ResultDelegate resul
49 45 }
50 46 else
51 47 {
52   - var bodyDelegate = (BodyDelegate) environment["owin.RequestBody"];
53 48 var request = new OwinRequestBody(environment);
54 49
55   - var bodyBuilder = request.GetRequestBodyBuilder();
56   - bodyDelegate(bodyBuilder, fault, () =>
  50 + var bodyDelegate = environment["owin.RequestBody"] as BodyDelegate;
  51 + if (bodyDelegate == null)
57 52 {
58   - var arguments = new OwinServiceArguments(routeData, request, response);
59   - var invoker = routeData.RouteHandler.As<FubuRouteHandler>().Invoker;
60   -
61   - try
62   - {
63   - invoker.Invoke(arguments, routeData.Values);
64   - }
65   - catch (Exception ex)
66   - {
67   - write500(response, ex);
68   - }
69   - finally
70   - {
71   - response.Finish();
72   - }
73   - });
  53 + executeRoute(routeData, response, request);
  54 + }
  55 + else
  56 + {
  57 + var bodyBuilder = request.GetRequestBodyBuilder();
  58 + bodyDelegate(bodyBuilder, fault, () => executeRoute(routeData, response, request));
  59 + }
74 60 }
75 61
76 62
77 63 if (Verbose) Console.WriteLine(" ({0})", response.Status);
78 64 }
79 65
  66 + private static void executeRoute(RouteData routeData, Response response, OwinRequestBody request)
  67 + {
  68 + var arguments = new OwinServiceArguments(routeData, request, response);
  69 + var invoker = routeData.RouteHandler.As<FubuRouteHandler>().Invoker;
  70 +
  71 + try
  72 + {
  73 + invoker.Invoke(arguments, routeData.Values);
  74 + }
  75 + catch (Exception ex)
  76 + {
  77 + write500(response, ex);
  78 + }
  79 + finally
  80 + {
  81 + response.Finish();
  82 + }
  83 + }
  84 +
80 85 private static void write500(Response response, Exception ex)
81 86 {
82 87 response.Status = "500";
@@ -101,8 +106,8 @@ private static void write404(Response response)
101 106 // TODO -- make this a lot smaller and bring over the UT's
102 107 public class Response
103 108 {
104   - readonly ResultDelegate _result;
105   - readonly Spool _spool = new Spool(true);
  109 + private readonly ResultDelegate _result;
  110 + private readonly Spool _spool = new Spool(true);
106 111
107 112 public Response(ResultDelegate result)
108 113 {
@@ -117,13 +122,19 @@ public Response(ResultDelegate result)
117 122 public IDictionary<string, string> Headers { get; set; }
118 123 public Encoding Encoding { get; set; }
119 124
120   - string GetHeader(string name)
  125 + public string ContentType
  126 + {
  127 + get { return GetHeader("Content-Type"); }
  128 + set { SetHeader("Content-Type", value); }
  129 + }
  130 +
  131 + private string GetHeader(string name)
121 132 {
122 133 string value;
123 134 return Headers.TryGetValue(name, out value) ? value : null;
124 135 }
125 136
126   - void SetHeader(string name, string value)
  137 + private void SetHeader(string name, string value)
127 138 {
128 139 if (string.IsNullOrWhiteSpace(value))
129 140 Headers.Remove(value);
@@ -131,12 +142,6 @@ void SetHeader(string name, string value)
131 142 Headers[name] = value;
132 143 }
133 144
134   - public string ContentType
135   - {
136   - get { return GetHeader("Content-Type"); }
137   - set { SetHeader("Content-Type", value); }
138   - }
139   -
140 145 public Response Write(string text)
141 146 {
142 147 // this could be more efficient if it spooled the immutable strings instead...
@@ -184,9 +189,9 @@ public void Finish(Action<Response, Action<Exception>, Action> body)
184 189
185 190 body(this, error, _spool.PushComplete);
186 191
187   - for (; ; )
  192 + for (;;)
188 193 {
189   - var count = new[] { 0 };
  194 + var count = new[]{0};
190 195 _spool.Pull(new ArraySegment<byte>(buffer), count, null);
191 196 if (count[0] == 0)
192 197 break;
@@ -203,7 +208,12 @@ public void Finish(Action<Response, Action<Exception>, Action> body)
203 208
204 209 public class Spool
205 210 {
206   - readonly bool _eagerPull;
  211 + private static readonly ArraySegment<byte> Empty = new ArraySegment<byte>(new byte[0], 0, 0);
  212 + private readonly AsyncOp _asyncPull = new AsyncOp();
  213 + private readonly AsyncOp _asyncPush = new AsyncOp();
  214 + private readonly Buffer _buffer = new Buffer();
  215 + private readonly bool _eagerPull;
  216 + private bool _complete;
207 217
208 218 public Spool()
209 219 {
@@ -361,7 +371,7 @@ public bool Pull(ArraySegment<byte> data, int[] retval, Action continuation)
361 371 }
362 372
363 373
364   - static void Drain(
  374 + private static void Drain(
365 375 ArraySegment<byte> source,
366 376 ArraySegment<byte> destination,
367 377 Action<ArraySegment<byte>, ArraySegment<byte>, int> result)
@@ -370,17 +380,18 @@ public bool Pull(ArraySegment<byte> data, int[] retval, Action continuation)
370 380 if (copied == 0) return;
371 381 Array.Copy(source.Array, source.Offset, destination.Array, destination.Offset, copied);
372 382 result(
373   - source.Count == copied ? Empty : new ArraySegment<byte>(source.Array, source.Offset + copied, source.Count - copied),
374   - destination.Count == copied ? Empty : new ArraySegment<byte>(destination.Array, destination.Offset + copied, destination.Count - copied),
  383 + source.Count == copied
  384 + ? Empty
  385 + : new ArraySegment<byte>(source.Array, source.Offset + copied, source.Count - copied),
  386 + destination.Count == copied
  387 + ? Empty
  388 + : new ArraySegment<byte>(destination.Array, destination.Offset + copied, destination.Count - copied),
375 389 copied);
376 390 }
377 391
378   - static readonly ArraySegment<byte> Empty = new ArraySegment<byte>(new byte[0], 0, 0);
  392 + #region Nested type: AsyncOp
379 393
380   - readonly AsyncOp _asyncPush = new AsyncOp();
381   - readonly AsyncOp _asyncPull = new AsyncOp();
382   -
383   - class AsyncOp
  394 + private class AsyncOp
384 395 {
385 396 public AsyncOp()
386 397 {
@@ -393,11 +404,11 @@ public AsyncOp()
393 404 public Action Continuation { get; set; }
394 405 }
395 406
  407 + #endregion
396 408
397   - readonly Buffer _buffer = new Buffer();
398   - bool _complete;
  409 + #region Nested type: Buffer
399 410
400   - class Buffer
  411 + private class Buffer
401 412 {
402 413 public Buffer()
403 414 {
@@ -424,5 +435,7 @@ public void Drain(ArraySegment<byte> data, Action<ArraySegment<byte>, int> resul
424 435 result(new ArraySegment<byte>(data.Array, data.Offset + copied, data.Count - copied), copied);
425 436 }
426 437 }
  438 +
  439 + #endregion
427 440 }
428 441 }
8 src/FubuMVC.OwinHost/IOwinRequestReader.cs
... ... @@ -0,0 +1,8 @@
  1 +namespace FubuMVC.OwinHost
  2 +{
  3 + public interface IOwinRequestReader
  4 + {
  5 + void Read(byte[] bytes, int offset, int count);
  6 + void Finish();
  7 + }
  8 +}
227 src/FubuMVC.OwinHost/OwinAggregateDictionary.cs
... ... @@ -1,237 +1,11 @@
1 1 using System;
2 2 using System.Collections.Generic;
3   -using System.Data;
4   -using System.IO;
5   -using System.Linq;
6   -using System.Text;
7 3 using System.Web.Routing;
8   -using FubuCore;
9 4 using FubuCore.Binding;
10 5 using FubuMVC.Core.Http;
11   -using FubuMVC.Core.Runtime;
12   -using Environment = Gate.Environment;
13 6
14 7 namespace FubuMVC.OwinHost
15 8 {
16   - public static class EnvironmentExtensions
17   - {
18   - public static string ContentType(this Environment environment)
19   - {
20   - string value;
21   - return (environment.Headers != null && environment.Headers.TryGetValue("Content-Type", out value))
22   - ? value
23   - : null;
24   - }
25   -
26   - public static T Get<T>(this Environment environment, string name)
27   - {
28   - object value;
29   - return environment.TryGetValue(name, out value) ? (T)value : default(T);
30   - }
31   - }
32   -
33   - public class OwinRequestBody
34   - {
35   - private static readonly char[] CommaSemicolon = new[]{',', ';'};
36   -
37   - private readonly string _contentType;
38   - private readonly Environment _environment;
39   - private readonly object _locker = new object();
40   - private readonly MemoryStream _stream = new MemoryStream();
41   - private readonly string _mediaType;
42   -
43   - public OwinRequestBody(Environment environment)
44   - {
45   - _environment = environment;
46   - _contentType = environment.ContentType();
47   -
48   - if (_contentType != null)
49   - {
50   - var delimiterPos = _contentType.IndexOfAny(CommaSemicolon);
51   - _mediaType = delimiterPos < 0 ? _contentType : _contentType.Substring(0, delimiterPos);
52   - }
53   - }
54   -
55   - public Environment Environment
56   - {
57   - get { return _environment; }
58   - }
59   -
60   - public bool HasFormData()
61   - {
62   - if (_mediaType == MimeType.HttpFormMimetype) return true;
63   - if (_mediaType == MimeType.MultipartMimetype) return true;
64   -
65   - if (string.Equals(_environment.Method, "POST", StringComparison.OrdinalIgnoreCase)) return true;
66   -
67   - return false;
68   - }
69   -
70   - public IOwinRequestReader DetermineReader()
71   - {
72   - var isFormData = _mediaType == MimeType.HttpFormMimetype || _mediaType == MimeType.MultipartMimetype;
73   -
74   - return isFormData
75   - ? (IOwinRequestReader) new FormRequestReader(dict => FormData = dict)
76   - : new StreamDataReader(_stream);
77   -
78   - }
79   -
80   - public IDictionary<string, string> FormData { get; private set; }
81   -
82   -
83   -
84   - public MemoryStream Stream
85   - {
86   - get { return _stream; }
87   - }
88   -
89   - public string PathBase
90   - {
91   - get { return _environment.PathBase; }
92   - }
93   -
94   - public string Path
95   - {
96   - get { return _environment.Path; }
97   - }
98   -
99   - public string HostWithPort
100   - {
101   - get
102   - {
103   - var headers = Headers();
104   -
105   - string hostHeader = null;
106   - if (headers.ContainsKey("Host"))
107   - {
108   - hostHeader = headers["Host"];
109   - }
110   -
111   - if (hostHeader.IsNotEmpty())
112   - {
113   - return hostHeader;
114   - }
115   -
116   - var serverName = _environment.Get<string>("server.SERVER_NAME");
117   - if (string.IsNullOrWhiteSpace(serverName))
118   - serverName = _environment.Get<string>("server.SERVER_ADDRESS");
119   - var serverPort = _environment.Get<string>("server.SERVER_PORT");
120   -
121   - return serverName + ":" + serverPort;
122   - }
123   - }
124   -
125   - public string Method
126   - {
127   - get { return _environment.Method; }
128   - }
129   -
130   -
131   - public Func<ArraySegment<byte>, Action, bool> GetRequestBodyBuilder()
132   - {
133   - var reader = DetermineReader();
134   -
135   -
136   - return (arraySegments, continuation) =>
137   - {
138   - reader.Read(arraySegments.Array, arraySegments.Offset, arraySegments.Count);
139   - if (continuation == null)
140   - {
141   - reader.Finish();
142   - return false;
143   - }
144   -
145   - continuation();
146   - return true;
147   - };
148   - }
149   -
150   - public IDictionary<string, string> Querystring()
151   - {
152   - var querystring = _environment.Get<string>("owin.RequestQueryString");
153   - return FormRequestReader.Parse(querystring);
154   - }
155   -
156   -
157   - public IDictionary<string, string> Headers()
158   - {
159   - return _environment.Headers ?? new Dictionary<string, string>();
160   - }
161   - }
162   -
163   - public interface IOwinRequestReader
164   - {
165   - void Read(byte[] bytes, int offset, int count);
166   - void Finish();
167   - }
168   -
169   - public class FormRequestReader : IOwinRequestReader
170   - {
171   - private readonly Action<IDictionary<string, string>> _finish;
172   - private readonly StringBuilder _builder;
173   - private readonly Encoding _encoding;
174   -
175   - public FormRequestReader(Action<IDictionary<string, string>> finish)
176   - {
177   - _finish = finish;
178   - _builder = new StringBuilder();
179   - _encoding = Encoding.UTF8; // TODO -- is this a good idea?
180   - }
181   -
182   - public void Read(byte[] bytes, int offset, int count)
183   - {
184   - var text = _encoding.GetString(bytes, offset, count);
185   - _builder.Append(text);
186   - }
187   -
188   - public IDictionary<string, string> PostData()
189   - {
190   - return Parse(_builder.ToString());
191   - }
192   -
193   - public static IDictionary<string, string> Parse(string queryString)
194   - {
195   - // TODO: this is wrong in many, many ways
196   - return (queryString ?? "").Split("&".ToCharArray())
197   - .Select(item => item.Split("=".ToCharArray(), 2))
198   - .Where(item => item.Length == 2)
199   - .GroupBy(item => item[0], item => Decode(item[1]), StringComparer.OrdinalIgnoreCase)
200   - .ToDictionary(g => g.Key, g => string.Join(",", g.ToArray()), StringComparer.OrdinalIgnoreCase);
201   -
202   - }
203   -
204   - static string Decode(string value)
205   - {
206   - return value.Replace("%3A", ":").Replace("%2F", "/");
207   - }
208   -
209   - public void Finish()
210   - {
211   - _finish(PostData());
212   - }
213   - }
214   -
215   - public class StreamDataReader : IOwinRequestReader
216   - {
217   - private readonly MemoryStream _stream;
218   -
219   - public StreamDataReader(MemoryStream stream)
220   - {
221   - _stream = stream;
222   - }
223   -
224   - public void Read(byte[] bytes, int offset, int count)
225   - {
226   - _stream.Write(bytes, offset, count);
227   - }
228   -
229   - public void Finish()
230   - {
231   -
232   - }
233   - }
234   -
235 9 public class OwinAggregateDictionary : AggregateDictionary
236 10 {
237 11 public OwinAggregateDictionary(RouteData routeData, OwinRequestBody body)
@@ -260,5 +34,4 @@ private void addDictionaryLocator(string name, IDictionary<string, string> dicti
260 34 AddLocator(name, locator, () => dictionary.Keys);
261 35 }
262 36 }
263   -
264 37 }
138 src/FubuMVC.OwinHost/OwinRequestBody.cs
... ... @@ -0,0 +1,138 @@
  1 +using System;
  2 +using System.Collections.Generic;
  3 +using System.IO;
  4 +using FubuCore;
  5 +using FubuMVC.Core.Runtime;
  6 +using Environment = Gate.Environment;
  7 +
  8 +namespace FubuMVC.OwinHost
  9 +{
  10 + public class OwinRequestBody
  11 + {
  12 + private static readonly char[] CommaSemicolon = new[]{',', ';'};
  13 +
  14 + private readonly string _contentType;
  15 + private readonly Environment _environment;
  16 + private readonly MemoryStream _stream = new MemoryStream();
  17 + private readonly string _mediaType;
  18 +
  19 + public OwinRequestBody(Environment environment)
  20 + {
  21 + _environment = environment;
  22 + _contentType = environment.ContentType();
  23 +
  24 + if (_contentType != null)
  25 + {
  26 + var delimiterPos = _contentType.IndexOfAny(CommaSemicolon);
  27 + _mediaType = delimiterPos < 0 ? _contentType : _contentType.Substring(0, delimiterPos);
  28 + }
  29 + }
  30 +
  31 + public Environment Environment
  32 + {
  33 + get { return _environment; }
  34 + }
  35 +
  36 + public bool HasFormData()
  37 + {
  38 + if (_mediaType == MimeType.HttpFormMimetype) return true;
  39 + if (_mediaType == MimeType.MultipartMimetype) return true;
  40 +
  41 + if (string.Equals(_environment.Method, "POST", StringComparison.OrdinalIgnoreCase)) return true;
  42 +
  43 + return false;
  44 + }
  45 +
  46 + public IOwinRequestReader DetermineReader()
  47 + {
  48 + var isFormData = _mediaType == MimeType.HttpFormMimetype || _mediaType == MimeType.MultipartMimetype;
  49 +
  50 + return isFormData
  51 + ? (IOwinRequestReader) new FormRequestReader(dict => FormData = dict)
  52 + : new StreamDataReader(_stream);
  53 +
  54 + }
  55 +
  56 + public IDictionary<string, string> FormData { get; private set; }
  57 +
  58 +
  59 +
  60 + public MemoryStream Stream
  61 + {
  62 + get { return _stream; }
  63 + }
  64 +
  65 + public string PathBase
  66 + {
  67 + get { return _environment.PathBase; }
  68 + }
  69 +
  70 + public string Path
  71 + {
  72 + get { return _environment.Path; }
  73 + }
  74 +
  75 + public string HostWithPort
  76 + {
  77 + get
  78 + {
  79 + var headers = Headers();
  80 +
  81 + string hostHeader = null;
  82 + if (headers.ContainsKey("Host"))
  83 + {
  84 + hostHeader = headers["Host"];
  85 + }
  86 +
  87 + if (hostHeader.IsNotEmpty())
  88 + {
  89 + return hostHeader;
  90 + }
  91 +
  92 + var serverName = _environment.Get<string>("server.SERVER_NAME");
  93 + if (string.IsNullOrWhiteSpace(serverName))
  94 + serverName = _environment.Get<string>("server.SERVER_ADDRESS");
  95 + var serverPort = _environment.Get<string>("server.SERVER_PORT");
  96 +
  97 + return serverName + ":" + serverPort;
  98 + }
  99 + }
  100 +
  101 + public string Method
  102 + {
  103 + get { return _environment.Method; }
  104 + }
  105 +
  106 +
  107 + public Func<ArraySegment<byte>, Action, bool> GetRequestBodyBuilder()
  108 + {
  109 + var reader = DetermineReader();
  110 +
  111 +
  112 + return (arraySegments, continuation) =>
  113 + {
  114 + reader.Read(arraySegments.Array, arraySegments.Offset, arraySegments.Count);
  115 + if (continuation == null)
  116 + {
  117 + reader.Finish();
  118 + return false;
  119 + }
  120 +
  121 + continuation();
  122 + return true;
  123 + };
  124 + }
  125 +
  126 + public IDictionary<string, string> Querystring()
  127 + {
  128 + var querystring = _environment.Get<string>("owin.RequestQueryString");
  129 + return FormRequestReader.Parse(querystring);
  130 + }
  131 +
  132 +
  133 + public IDictionary<string, string> Headers()
  134 + {
  135 + return _environment.Headers ?? new Dictionary<string, string>();
  136 + }
  137 + }
  138 +}
24 src/FubuMVC.OwinHost/StreamDataReader.cs
... ... @@ -0,0 +1,24 @@
  1 +using System.IO;
  2 +
  3 +namespace FubuMVC.OwinHost
  4 +{
  5 + public class StreamDataReader : IOwinRequestReader
  6 + {
  7 + private readonly MemoryStream _stream;
  8 +
  9 + public StreamDataReader(MemoryStream stream)
  10 + {
  11 + _stream = stream;
  12 + }
  13 +
  14 + public void Read(byte[] bytes, int offset, int count)
  15 + {
  16 + _stream.Write(bytes, offset, count);
  17 + }
  18 +
  19 + public void Finish()
  20 + {
  21 +
  22 + }
  23 + }
  24 +}
2  src/KayakTestApplication/KayakApplication.cs
@@ -21,7 +21,7 @@ public class KayakRegistry : FubuRegistry
21 21 {
22 22 public KayakRegistry()
23 23 {
24   - Route("").Calls<SayHelloController>(x => x.Hello());
  24 + Routes.HomeIs<SayHelloController>(x => x.Hello());
25 25
26 26 Actions.IncludeClassesSuffixedWithController();
27 27 this.UseSpark();
7 src/Serenity.Testing/InProcessSerenitySystemTester.cs
@@ -55,5 +55,12 @@ public void can_post()
55 55
56 56 Debug.WriteLine(response.ToString());
57 57 }
  58 +
  59 + [Test]
  60 + public void can_get_with_no_body()
  61 + {
  62 + theDriver.GetEndpointDriver().ReadTextFrom<SayHelloController>(x => x.Hello())
  63 + .ShouldStartWith("Hello");
  64 + }
58 65 }
59 66 }
7 src/Serenity/Endpoints/EndpointDriver.cs
... ... @@ -1,6 +1,7 @@
1 1 using System;
2 2 using System.Collections.Generic;
3 3 using System.IO;
  4 +using System.Linq.Expressions;
4 5 using System.Net;
5 6 using System.Text;
6 7 using System.Web;
@@ -83,6 +84,12 @@ public string ReadTextFrom(object input)
83 84 return new WebClient().DownloadString(url);
84 85 }
85 86
  87 + public string ReadTextFrom<T>(Expression<Action<T>> expression)
  88 + {
  89 + var url = _urls.UrlFor(expression);
  90 + return new WebClient().DownloadString(url);
  91 + }
  92 +
86 93
87 94
88 95 private HttpResponse post(object urlTarget, string contentType, string accept, Action<Stream> setRequest)

0 comments on commit 5cb4aa4

Please sign in to comment.
Something went wrong with that request. Please try again.