Skip to content

Commit e7f5375

Browse files
author
Don Clore
committed
master - adding Sid
1 parent 27b73d8 commit e7f5375

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+3148
-0
lines changed

Sid/LICENSE

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) 2015 doncl
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.
22+

Sid/README.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Sid is a very lightweight C# RESTful framework.
2+
It works on both Mono and .NET, with Mono/Linux being the primary intended target.
3+
To create an endpoint:
4+
5+
0. Create a subclass of SidModule.
6+
1. Give your class a RootPath attribute (see TestModule.cs).
7+
2. Add method/endpoint(s). Do NOT declare them as public, or Sid won't use them.
8+
3. Use the various attributes (Get, Put, Post, etc.) implemented in the Declarations subdirectory to
9+
fully describe a route for your endpoint(s).
10+
4. Your endpoint(s) can take arguments as
11+
a. PathAttributes (the argument is on the path - see GetTestObject() for a simple example).
12+
b. QueryAttributes (the argument is on the querystring). Just declare a parameter with [Query] in
13+
your method signature.
14+
c. BindAttributes - these are POST or PUT bodies, just declare a [Bind] parameter on your function that
15+
is some C# class, and the plumbing will deserialize it for you. If it's a flat list of key-value
16+
pairs, it can also be called from the querystring, and the system will use it.
17+
d. HeaderAttributes - again, declare it in your method signature, and the system will look for an HTTP
18+
header with that name.
19+
e. CookieAttributes - hopefully this is self-explanatory by now.
20+
21+
5. To run things, create an instance of the WebService object, and call Run(). It's asynchronous, so you'll
22+
need to arrange for you main thread not to die and take everything down with it (Console.ReadKey() is the
23+
simplest, crudest way to do this), or sleep in a loop, waiting for interrupt, however you like.
24+
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
using System.Reflection;
2+
using System.Runtime.CompilerServices;
3+
4+
// Information about this assembly is defined by the following attributes.
5+
// Change them to the values specific to your project.
6+
7+
[assembly: AssemblyTitle("Sid.Tests")]
8+
[assembly: AssemblyDescription("")]
9+
[assembly: AssemblyConfiguration("")]
10+
[assembly: AssemblyCompany("")]
11+
[assembly: AssemblyProduct("")]
12+
[assembly: AssemblyCopyright("doncl")]
13+
[assembly: AssemblyTrademark("")]
14+
[assembly: AssemblyCulture("")]
15+
16+
// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
17+
// The form "{Major}.{Minor}.*" will automatically update the build and revision,
18+
// and "{Major}.{Minor}.{Build}.*" will update just the revision.
19+
20+
[assembly: AssemblyVersion("1.0.*")]
21+
22+
// The following attributes are used to specify the signing key for the assembly,
23+
// if desired. See the Mono documentation for more information about signing.
24+
25+
//[assembly: AssemblyDelaySign(false)]
26+
//[assembly: AssemblyKeyFile("")]
27+
Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Collections.Specialized;
4+
using System.IO;
5+
using System.Net.Http;
6+
using System.Text;
7+
using Sid.WebServices;
8+
using System.Reflection;
9+
10+
namespace Sid.WebServices.Test
11+
{
12+
/// <summary>
13+
/// This is code cobbled together from the nancy test framework for use in our integration
14+
/// tests; as little of this code is used as possible.
15+
/// </summary>
16+
public class Browser
17+
{
18+
public RestfulMethodDispatcher MethodDispatcher {get; set;}
19+
20+
public Browser(IEnumerable<Assembly> sidModuleAssemblies)
21+
{
22+
MethodDispatcher = new RestfulMethodDispatcher(sidModuleAssemblies) {
23+
IsValidOrigin = (req, uri) => true,
24+
};
25+
}
26+
27+
/// <summary>
28+
/// Performs a DELETE requests.
29+
/// </summary>
30+
/// <param name="path">The path that is being requested.</param>
31+
/// <param name="browserContext">An closure for providing browser context for the
32+
/// request.</param>
33+
/// <returns>An <see cref="BrowserResponse"/> instance of the executed request.
34+
/// </returns>
35+
public BrowserResponse Delete(string path,
36+
Action<BrowserContext> browserContext = null)
37+
{
38+
return HandleRequest(HttpMethod.Delete, path, browserContext);
39+
}
40+
41+
/// <summary>
42+
/// Performs a GET request.
43+
/// </summary>
44+
/// <param name="path">The path that is being requested.</param>
45+
/// <param name="browserContext">An closure for providing browser context for the
46+
/// request.</param>
47+
/// <returns>An <see cref="BrowserResponse"/> instance of the executed request.
48+
/// </returns>
49+
public BrowserResponse Get(string path, Action<BrowserContext> browserContext = null)
50+
{
51+
return HandleRequest(HttpMethod.Get, path, browserContext);
52+
}
53+
54+
/// <summary>
55+
/// Performs an OPTIONS request.
56+
/// </summary>
57+
/// <param name="path">The path that is being requested.</param>
58+
/// <param name="browserContext">An closure for providing browser context for the
59+
/// request.</param>
60+
/// <returns>An <see cref="BrowserResponse"/> instance of the executed request.
61+
/// </returns>
62+
public BrowserResponse Options(string path,
63+
Action<BrowserContext> browserContext = null)
64+
{
65+
return HandleRequest(HttpMethod.Options, path, browserContext);
66+
}
67+
68+
/// <summary>
69+
/// Performs a POST request.
70+
/// </summary>
71+
/// <param name="path">The path that is being requested.</param>
72+
/// <param name="browserContext">An closure for providing browser context for the
73+
/// request.</param>
74+
/// <returns>An <see cref="BrowserResponse"/> instance of the executed request.
75+
/// </returns>
76+
public BrowserResponse Post(string path, Action<BrowserContext> browserContext = null)
77+
{
78+
return HandleRequest(HttpMethod.Post, path, browserContext);
79+
}
80+
81+
/// <summary>
82+
/// Performs a PUT request.
83+
/// </summary>
84+
/// <param name="path">The path that is being requested.</param>
85+
/// <param name="browserContext">An closure for providing browser context for the
86+
/// request.</param>
87+
/// <returns>An <see cref="BrowserResponse"/>Instance of the executed request.
88+
/// </returns>
89+
public BrowserResponse Put(string path, Action<BrowserContext> browserContext = null)
90+
{
91+
return HandleRequest(HttpMethod.Put, path, browserContext);
92+
}
93+
94+
private BrowserResponse HandleRequest(HttpMethod method, string path,
95+
Action<BrowserContext> browserContext)
96+
{
97+
var request =
98+
CreateRequest(method, path, browserContext ?? DefaultBrowserContext);
99+
100+
var restfulResponse = MethodDispatcher.ResolveRequest(request);
101+
var response = new BrowserResponse{
102+
StatusCode = restfulResponse.StatusCode,
103+
Body = restfulResponse.Body,
104+
Headers = new NameValueCollection(),
105+
};
106+
107+
if (restfulResponse.Headers != null) {
108+
foreach (var header in restfulResponse.Headers) {
109+
response.Headers.Add(header.Key, header.Value);
110+
}
111+
}
112+
113+
return response;
114+
}
115+
116+
private void DefaultBrowserContext(BrowserContext context)
117+
{
118+
context.HttpRequest();
119+
}
120+
121+
private static void BuildRequestBody(IBrowserContextValues contextValues)
122+
{
123+
if (contextValues.Body != null) {
124+
return;
125+
}
126+
127+
if (string.IsNullOrEmpty(contextValues.BodyString)) {
128+
contextValues.Body = Stream.Null;
129+
} else {
130+
var bodyContents = contextValues.BodyString;
131+
var bodyBytes = bodyContents != null ? Encoding.UTF8.GetBytes(bodyContents) :
132+
new byte[] { };
133+
134+
contextValues.Body = new MemoryStream(bodyBytes);
135+
}
136+
}
137+
138+
private RestfulTestServerRequest CreateRequest(HttpMethod method, string path,
139+
Action<BrowserContext> browserContext)
140+
{
141+
var context =
142+
new BrowserContext();
143+
144+
browserContext.Invoke(context);
145+
146+
var contextValues =
147+
(IBrowserContextValues)context;
148+
149+
if (String.IsNullOrEmpty(contextValues.UserHostAddress)) {
150+
throw new Exception("Need a valid host address");
151+
}
152+
153+
path = path.TrimStart('/');
154+
var uriString = contextValues.Protocol + "://" + contextValues.UserHostAddress +
155+
"/" + path;
156+
157+
Uri uri;
158+
159+
if (!Uri.TryCreate(uriString, UriKind.Absolute, out uri)) {
160+
throw new Exception(String.Format("Cannot create uri from {0}", uri));
161+
}
162+
163+
BuildRequestBody(contextValues);
164+
165+
var queryString = contextValues.QueryString.ToRestValueCollectionNoSplitOnCommas();
166+
var headers = contextValues.Headers.ToRestValueCollectionSplitOnCommas();
167+
headers["Origin"] = new [] {"http://" + path.TrimStart('/')};
168+
169+
return new RestfulTestServerRequest{
170+
Url = uri,
171+
Cookies = contextValues.Cookies,
172+
HttpMethod = method,
173+
InputStream = contextValues.Body,
174+
RawUrl= path,
175+
Headers = headers,
176+
QueryString = queryString,
177+
};
178+
}
179+
}
180+
}
181+

0 commit comments

Comments
 (0)