Skip to content

Commit 429d7da

Browse files
committed
Modified Interfaces, Using Tasks for better thread scalability.
1 parent 352d0e0 commit 429d7da

File tree

14 files changed

+175
-148
lines changed

14 files changed

+175
-148
lines changed

uhttpsharp-demo/AboutHandler.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,15 @@
1616
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1717
*/
1818

19+
using System.Threading.Tasks;
1920
using uhttpsharp;
2021

2122
namespace uhttpsharpdemo
2223
{
23-
[HttpRequestHandlerAttributes("about")]
24-
public class AboutHandler : HttpRequestHandler
24+
public class AboutHandler : IHttpRequestHandler
2525
{
26-
public override HttpResponse Handle(HttpRequest httpRequest)
26+
27+
public async Task<HttpResponse> Handle(HttpRequest httpRequest, System.Func<Task<HttpResponse>> next)
2728
{
2829
return HttpResponse.CreateWithMessage(HttpResponseCode.Ok, "Sample http-request-handler");
2930
}

uhttpsharp-demo/ErrorHandler.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,14 @@
1616
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1717
*/
1818

19+
using System.Threading.Tasks;
1920
using uhttpsharp;
2021

2122
namespace uhttpsharpdemo
2223
{
23-
[HttpRequestHandlerAttributes("404")]
24-
public class ErrorHandler : HttpRequestHandler
24+
public class ErrorHandler : IHttpRequestHandler
2525
{
26-
public override HttpResponse Handle(HttpRequest httpRequest)
26+
public async Task<HttpResponse> Handle(HttpRequest httpRequest, System.Func<System.Threading.Tasks.Task<HttpResponse>> next)
2727
{
2828
return new HttpResponse(HttpResponseCode.NotFound, "These are not the droids you are looking for.");
2929
}

uhttpsharp-demo/FileHandler.cs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,12 @@
1818

1919
using System.Collections.Generic;
2020
using System.IO;
21+
using System.Threading.Tasks;
2122
using uhttpsharp;
2223

2324
namespace uhttpsharpdemo
2425
{
25-
[HttpRequestHandlerAttributes("*")]
26-
public class FileHandler : HttpRequestHandler
26+
public class FileHandler : IHttpRequestHandler
2727
{
2828
public static string DefaultMimeType { get; set; }
2929
public static string HttpRootDirectory { get; set; }
@@ -52,13 +52,16 @@ private string GetContentType(string path)
5252
return MimeTypes[extension];
5353
return DefaultMimeType;
5454
}
55-
public override HttpResponse Handle(HttpRequest httpRequest)
55+
public async Task<HttpResponse> Handle(HttpRequest httpRequest, System.Func<Task<HttpResponse>> next)
5656
{
57+
var requestPath = httpRequest.Uri.OriginalString.TrimStart('/');
58+
5759
var httpRoot = Path.GetFullPath(HttpRootDirectory ?? ".");
58-
var requestPath = httpRequest.Uri.AbsolutePath.TrimStart('/');
5960
var path = Path.GetFullPath(Path.Combine(httpRoot, requestPath));
61+
6062
if (!File.Exists(path))
61-
return null;
63+
return await next();
64+
6265
return new HttpResponse(GetContentType(path), File.OpenRead(path));
6366
}
6467
}

uhttpsharp-demo/IndexHandler.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,10 @@
2020

2121
namespace uhttpsharpdemo
2222
{
23-
[HttpRequestHandlerAttributes("")]
24-
public class IndexHandler : HttpRequestHandler
23+
public class IndexHandler : IHttpRequestHandler
2524
{
26-
public override HttpResponse Handle(HttpRequest httpRequest)
25+
26+
public async System.Threading.Tasks.Task<HttpResponse> Handle(HttpRequest httpRequest, System.Func<System.Threading.Tasks.Task<HttpResponse>> next)
2727
{
2828
return new HttpResponse(HttpResponseCode.Ok, "Welcome to the Index. ☺");
2929
}

uhttpsharp-demo/Program.cs

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717
*/
1818

1919
using System;
20+
using System.Diagnostics;
21+
using System.IO.Ports;
22+
using System.Net;
2023
using System.Net.Sockets;
2124
using uhttpsharp;
2225

@@ -28,10 +31,17 @@ private static void Main()
2831
{
2932
for (var port = 8000; port <= 65535; ++port)
3033
{
31-
HttpServer.Instance.Port = port;
34+
var httpServer = new HttpServer(port);
35+
36+
httpServer.Use(new TimingHandler());
37+
httpServer.Use(new HttpRouter().With(string.Empty, new IndexHandler())
38+
.With("about", new AboutHandler()));
39+
httpServer.Use(new FileHandler());
40+
httpServer.Use(new ErrorHandler());
41+
3242
try
3343
{
34-
HttpServer.Instance.StartUp();
44+
httpServer.Start();
3545
}
3646
catch (SocketException)
3747
{
@@ -42,4 +52,16 @@ private static void Main()
4252
Console.ReadLine();
4353
}
4454
}
55+
56+
public class TimingHandler : IHttpRequestHandler
57+
{
58+
59+
public async System.Threading.Tasks.Task<HttpResponse> Handle(HttpRequest httpRequest, Func<System.Threading.Tasks.Task<HttpResponse>> next)
60+
{
61+
var stopWatch = Stopwatch.StartNew();
62+
var retVal = await next();
63+
Console.WriteLine(stopWatch.Elapsed);
64+
return retVal;
65+
}
66+
}
4567
}

uhttpsharp-demo/app.config

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<configuration>
3+
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/></startup></configuration>

uhttpsharp-demo/uhttpsharp-demo.csproj

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@
1010
<AppDesignerFolder>Properties</AppDesignerFolder>
1111
<RootNamespace>uhttpsharpdemo</RootNamespace>
1212
<AssemblyName>uhttpsharp-demo</AssemblyName>
13-
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
14-
<TargetFrameworkProfile>Client</TargetFrameworkProfile>
13+
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
14+
<TargetFrameworkProfile>
15+
</TargetFrameworkProfile>
1516
<FileAlignment>512</FileAlignment>
1617
</PropertyGroup>
1718
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
@@ -23,6 +24,7 @@
2324
<DefineConstants>DEBUG;TRACE</DefineConstants>
2425
<ErrorReport>prompt</ErrorReport>
2526
<WarningLevel>4</WarningLevel>
27+
<Prefer32Bit>false</Prefer32Bit>
2628
</PropertyGroup>
2729
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
2830
<PlatformTarget>x86</PlatformTarget>
@@ -32,6 +34,7 @@
3234
<DefineConstants>TRACE</DefineConstants>
3335
<ErrorReport>prompt</ErrorReport>
3436
<WarningLevel>4</WarningLevel>
37+
<Prefer32Bit>false</Prefer32Bit>
3538
</PropertyGroup>
3639
<ItemGroup>
3740
<Reference Include="System" />
@@ -59,6 +62,9 @@
5962
<Name>uhttpsharp</Name>
6063
</ProjectReference>
6164
</ItemGroup>
65+
<ItemGroup>
66+
<None Include="app.config" />
67+
</ItemGroup>
6268
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
6369
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
6470
Other similar extension points exist, see Microsoft.Common.targets.

uhttpsharp/HttpClient.cs

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,13 @@
1616
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1717
*/
1818

19+
using System;
20+
using System.Collections.Generic;
1921
using System.IO;
22+
using System.Linq;
2023
using System.Net.Sockets;
2124
using System.Threading;
25+
using System.Threading.Tasks;
2226

2327
namespace uhttpsharp
2428
{
@@ -27,17 +31,16 @@ public sealed class HttpClient
2731
private readonly TcpClient _client;
2832
private readonly Stream _inputStream;
2933
private readonly Stream _outputStream;
30-
private readonly HttpRouter _router;
34+
private readonly IList<IHttpRequestHandler> _requestHandlers;
3135

32-
public HttpClient(TcpClient client)
36+
public HttpClient(TcpClient client, IList<IHttpRequestHandler> requestHandlers)
3337
{
3438
_client = client;
35-
_inputStream = new BufferedStream(_client.GetStream());
39+
_requestHandlers = requestHandlers;
3640
_outputStream = _client.GetStream();
37-
_router = new HttpRouter();
41+
_inputStream = new BufferedStream(_client.GetStream());
3842

39-
var clientThread = new Thread(Process) {IsBackground = true};
40-
clientThread.Start();
43+
Task.Factory.StartNew(Process);
4144
}
4245

4346
private void Process()
@@ -54,22 +57,42 @@ private void Process()
5457
// Socket exceptions on read will be re-thrown as IOException by BufferedStream
5558
}
5659
}
57-
private void ProcessInternal()
60+
61+
62+
private Func<Task<HttpResponse>> BuildHandlers(HttpRequest request, int index = 0)
63+
{
64+
if (index > _requestHandlers.Count)
65+
{
66+
return null;
67+
}
68+
69+
return () => _requestHandlers[index].Handle(request, BuildHandlers(request, index + 1));
70+
}
71+
72+
private async void ProcessInternal()
5873
{
5974
while (_client.Connected)
6075
{
61-
var request = new HttpRequest(_inputStream);
76+
var request = await HttpRequest.Build(_inputStream);
6277
if (request.Valid)
6378
{
64-
var response = _router.Route(request);
79+
var getResponse = BuildHandlers(request)();
80+
81+
var response = await getResponse;
82+
6583
if (response != null)
6684
{
67-
response.WriteResponse(_outputStream);
68-
if (response.CloseConnection) _client.Close();
85+
await response.WriteResponse(_outputStream);
86+
if (response.CloseConnection)
87+
{
88+
_client.Close();
89+
}
6990
}
7091
}
7192
else
93+
{
7294
_client.Close();
95+
}
7396
}
7497
}
7598
}

uhttpsharp/HttpRequest.cs

Lines changed: 22 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,20 @@
1919
using System;
2020
using System.Collections.Generic;
2121
using System.IO;
22+
using System.Threading.Tasks;
2223

2324
namespace uhttpsharp
2425
{
2526
public sealed class HttpRequest
2627
{
28+
public static async Task<HttpRequest> Build(Stream stream)
29+
{
30+
var retVal = new HttpRequest(stream);
31+
await retVal.Process();
32+
33+
return retVal;
34+
}
35+
2736
public bool Valid { get; private set; }
2837
public Dictionary<string, string> Headers { get; private set; }
2938
public HttpMethod HttpMethod { get; private set; }
@@ -33,20 +42,21 @@ public sealed class HttpRequest
3342
public HttpRequestParameters Parameters { get; private set; }
3443

3544
private readonly Stream _stream;
45+
private readonly StreamReader _streamReader;
3646

3747
public HttpRequest(Stream stream)
3848
{
3949
Headers = new Dictionary<string, string>();
4050
_stream = stream;
41-
Process();
51+
_streamReader = new StreamReader(_stream);
4252
}
4353

44-
private void Process()
54+
private async Task Process()
4555
{
4656
Valid = false;
4757

4858
// parse the http request
49-
var request = ReadLine();
59+
var request = await _streamReader.ReadLineAsync();
5060
if (request == null)
5161
return;
5262
var tokens = request.Split(' ');
@@ -69,43 +79,30 @@ private void Process()
6979

7080
HttpProtocol = tokens[2];
7181
URL = tokens[1];
72-
Uri = new Uri("http://" + HttpServer.Instance.Address + "/" + URL.TrimStart('/'));
82+
Uri = new Uri(URL, UriKind.Relative);
83+
7384
Parameters = new HttpRequestParameters(URL);
7485

75-
Console.WriteLine(string.Format("[{0}:{1}] URL: {2}", HttpProtocol, HttpMethod, URL));
86+
Console.WriteLine("[{0}:{1}] URL: {2}", HttpProtocol, HttpMethod, URL);
7687

7788
// get the headers
7889
string line;
79-
while ((line = ReadLine()) != null)
90+
while ((line = await _streamReader.ReadLineAsync()) != null)
8091
{
81-
if (line.Equals("")) break;
92+
if (line.Equals(string.Empty)) break;
8293
var keys = line.Split(':');
8394
Headers.Add(keys[0], keys[1]);
8495
}
8596

8697
Valid = true;
8798
}
8899

89-
private string ReadLine()
100+
private KeyValuePair<string, string> SplitHeader(string header)
90101
{
91-
var buffer = string.Empty;
92-
93-
while (true)
94-
{
95-
var _char = _stream.ReadByte();
96-
if (_char == '\n') break;
97-
if (_char == '\r') continue;
98-
if (_char == -1)
99-
{
100-
if (buffer != string.Empty)
101-
return buffer;
102-
return null;
103-
}
104-
buffer += Convert.ToChar(_char);
105-
}
106-
107-
return buffer;
102+
var index = header.IndexOf(':');
103+
return new KeyValuePair<string, string>(header.Substring(0, index), header.Substring(index + 1));
108104
}
105+
109106
}
110107

111108
public enum HttpMethod

uhttpsharp/HttpRequestHandler.cs

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -17,25 +17,12 @@
1717
*/
1818

1919
using System;
20+
using System.Threading.Tasks;
2021

2122
namespace uhttpsharp
2223
{
23-
public class HttpRequestHandler
24+
public interface IHttpRequestHandler
2425
{
25-
public virtual HttpResponse Handle(HttpRequest httpRequest)
26-
{
27-
throw new NotImplementedException();
28-
}
29-
}
30-
31-
[AttributeUsage(AttributeTargets.Class)]
32-
public class HttpRequestHandlerAttributes : Attribute
33-
{
34-
public string Function { get; private set; }
35-
36-
public HttpRequestHandlerAttributes(string functionName)
37-
{
38-
Function = functionName;
39-
}
26+
Task<HttpResponse> Handle(HttpRequest httpRequest, Func<Task<HttpResponse>> next);
4027
}
4128
}

0 commit comments

Comments
 (0)