Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge pull request #386 from kouphax/master

Nancy.Jsonp
  • Loading branch information...
commit caefb1eabfbd8084c4bc8054b6885139131534a1 2 parents 860429c + e582bc8
@grumpydev grumpydev authored
View
16 src/Nancy.Tests.Functional/Modules/JsonpTestModule.cs
@@ -0,0 +1,16 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Nancy.Tests.Functional.Modules
+{
+ public class JsonpTestModule : NancyModule
+ {
+ public JsonpTestModule() : base("/test")
+ {
+ Get["/string"] = x => "Normal Response";
+ Get["/json"] = x => Response.AsJson(true);
+ }
+ }
+}
View
3  src/Nancy.Tests.Functional/Nancy.Tests.Functional.csproj
@@ -49,6 +49,8 @@
<Compile Include="..\SharedAssemblyInfo.cs">
<Link>Properties\SharedAssemblyInfo.cs</Link>
</Compile>
+ <Compile Include="Modules\JsonpTestModule.cs" />
+ <Compile Include="Tests\JsonpTests.cs" />
<Compile Include="Tests\StaticContentTests.cs" />
</ItemGroup>
<ItemGroup>
@@ -70,7 +72,6 @@
</Content>
</ItemGroup>
<ItemGroup>
- <Folder Include="Modules\" />
<Folder Include="Views\" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
View
68 src/Nancy.Tests.Functional/Tests/JsonpTests.cs
@@ -0,0 +1,68 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Nancy.Bootstrapper;
+using Nancy.Testing;
+using Nancy.Tests.Functional.Modules;
+using Xunit;
+
+namespace Nancy.Tests.Functional.Tests
+{
+ public class JsonpTests
+ {
+ private readonly INancyBootstrapper bootstrapper;
+
+ private readonly Browser browser;
+
+ public JsonpTests()
+ {
+ this.bootstrapper = new ConfigurableBootstrapper(
+ configuration =>
+ {
+ configuration.Modules(new Type[] { typeof(JsonpTestModule) });
+ });
+
+ this.browser = new Browser(bootstrapper);
+ }
+
+ [Fact]
+ public void Ensure_that_Jsonp_hook_does_not_affect_normal_responses()
+ {
+ var result = browser.Get("/test/string", c =>
+ {
+ c.HttpRequest();
+ });
+
+ Assert.Equal(HttpStatusCode.OK, result.StatusCode);
+ Assert.Equal("Normal Response", result.Body.AsString());
+ }
+
+ [Fact]
+ public void Ensure_that_Jsonp_hook_does_not_affect_a_normal_json_response()
+ {
+ var result = browser.Get("/test/json", c =>
+ {
+ c.HttpRequest();
+ });
+
+ Assert.Equal(HttpStatusCode.OK, result.StatusCode);
+ Assert.Equal("true", result.Body.AsString());
+ Assert.Equal("application/json", result.Context.Response.ContentType);
+ }
+
+ [Fact]
+ public void Ensure_that_Jsonp_hook_should_pad_a_json_response_when_callback_is_present()
+ {
+ var result = browser.Get("/test/json", with =>
+ {
+ with.HttpRequest();
+ with.Query("callback", "myCallback");
+ });
+
+ Assert.Equal(HttpStatusCode.OK, result.StatusCode);
+ Assert.Equal("myCallback(true);", result.Body.AsString());
+ Assert.Equal("application/javascript", result.Context.Response.ContentType);
+ }
+ }
+}
View
75 src/Nancy/Jsonp.cs
@@ -0,0 +1,75 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Nancy.Bootstrapper;
+using System.IO;
+
+namespace Nancy
+{
+ public static class Jsonp
+ {
+ static PipelineItem<Action<NancyContext>> JsonpItem;
+
+ static Jsonp()
+ {
+ JsonpItem = new PipelineItem<Action<NancyContext>>("JSONP", PrepareJsonp);
+ }
+
+ /// <summary>
+ /// Enable JSONP support in the application
+ /// </summary>
+ /// <param name="pipeline">Application Pipeline to Hook into</param>
+ public static void Enable(IPipelines pipelines)
+ {
+ bool jsonpEnabled = pipelines.AfterRequest.PipelineItems.Any(ctx => ctx.Name == "JSONP");
+
+ if (!jsonpEnabled)
+ {
+ pipelines.AfterRequest.AddItemToEndOfPipeline(JsonpItem);
+ }
+ }
+
+ /// <summary>
+ /// Disable JSONP support in the application
+ /// </summary>
+ /// <param name="pipeline">Application Pipeline to Hook into</param>
+ public static void Disable(IPipelines pipelines)
+ {
+ pipelines.AfterRequest.RemoveByName("JSONP");
+ }
+
+ /// <summary>
+ /// Transmogrify original response and apply JSONP Padding
+ /// </summary>
+ /// <param name="context">Current Nancy Context</param>
+ private static void PrepareJsonp(NancyContext context)
+ {
+ bool isJson = context.Response.ContentType == "application/json";
+ bool hasCallback = context.Request.Query["callback"].HasValue;
+
+ if (isJson && hasCallback)
+ {
+ // grab original contents for running later
+ Action<Stream> original = context.Response.Contents;
+ string callback = context.Request.Query["callback"].Value;
+
+ // set content type to application/javascript so browsers can handle it by default
+ // http://stackoverflow.com/questions/111302/best-content-type-to-serve-jsonp
+ context.Response.ContentType = "application/javascript";
+ context.Response.Contents = stream =>
+ {
+ // disposing of stream is handled elsewhere
+ StreamWriter writer = new StreamWriter(stream)
+ {
+ AutoFlush = true
+ };
+
+ writer.Write("{0}(", callback);
+ original(stream);
+ writer.Write(");");
+ };
+ }
+ }
+ }
+}
View
33 src/Nancy/JsonpStartup.cs
@@ -0,0 +1,33 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Nancy.Bootstrapper;
+using Nancy.Responses;
+using System.IO;
+
+namespace Nancy
+{
+ public class JsonpStartup : IStartup
+ {
+ public IEnumerable<TypeRegistration> TypeRegistrations
+ {
+ get { return null; }
+ }
+
+ public IEnumerable<CollectionTypeRegistration> CollectionTypeRegistrations
+ {
+ get { return null; }
+ }
+
+ public IEnumerable<InstanceRegistration> InstanceRegistrations
+ {
+ get { return null; }
+ }
+
+ public void Initialize(IPipelines pipelines)
+ {
+ Nancy.Jsonp.Enable(pipelines);
+ }
+ }
+}
View
2  src/Nancy/Nancy.csproj
@@ -101,6 +101,8 @@
<Compile Include="Conventions\StaticContentConventionBuilder.cs" />
<Compile Include="DefaultResponseFormatterFactory.cs" />
<Compile Include="IResponseFormatterFactory.cs" />
+ <Compile Include="Jsonp.cs" />
+ <Compile Include="JsonpStartup.cs" />
<Compile Include="Responses\StreamResponse.cs" />
<Compile Include="IO\UnclosableStreamWrapper.cs" />
<Compile Include="ISerializer.cs" />
Please sign in to comment.
Something went wrong with that request. Please try again.