Skip to content

Added ignore of WEB-INF directory for Railo installations #50

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 82 commits into from
Closed
Changes from all commits
Commits
Show all changes
82 commits
Select commit Hold shift + click to select a range
993bbbe
generalized locally used version of jquery
Mar 15, 2011
bd7bdb1
proof of concept for binary returns, like images.
Mar 16, 2011
aebeb19
added custom mime handling for binary returns
Mar 16, 2011
6de855f
renamed img.cfc to kitten.cfc ^___^ mew
Mar 16, 2011
5f46432
started to implement PlaceKitten but not fully working yet
Mar 21, 2011
54f864e
adding example of requiring an api key
Mar 21, 2011
33f0f37
switch example resource to a more interesting one
Mar 21, 2011
b4f60ea
reload app settings when reloading framework
Mar 22, 2011
1396eb2
enable custom status text
Mar 22, 2011
3bd6eb0
New example showing how you might implement rate limiting
Mar 22, 2011
a147462
remove debug stuff
Mar 22, 2011
22fde49
changed rate limiting period to something easier to explain
Mar 23, 2011
85eb89e
fixed an image scaling bug. that was stupid.
Mar 23, 2011
dbdabe5
added (apache) urlrewriting for all examples
Mar 23, 2011
a23d4eb
changed metadata attributes in snippets because colon isn't supported…
Mar 24, 2011
3843d51
update rewrite rules to allow direct linking of images (for pdf creat…
Mar 24, 2011
12449b2
fixed a bug where reloading the API did not re-run app startup event
Mar 31, 2011
7ce5e5d
more explicitly define coldspring config location
Mar 31, 2011
db13404
if browsing to the root of the api folder, redirect to the dashboard
Mar 31, 2011
0913d8f
renamed two-factory example to be less confusing with two-return form…
Mar 31, 2011
e18ac91
renamed two-format example to be less confusing with two-factory example
Mar 31, 2011
5a205ec
renamed example collection to be less offensive
Mar 31, 2011
9537a7d
remove examples of defaults in complex example app, they don't add an…
Mar 31, 2011
bee8c45
allow app reinit, clear taffy from memory on reinit
Mar 31, 2011
a2f2891
merge binary returns dev branch into 1.1 release candidate branch
Mar 31, 2011
0f6374c
remove mod_rewrite setup because of conflicts
Mar 31, 2011
a1e9c65
fix bug where new dashboard redirect breaks DMZ paths
Mar 31, 2011
5b13fff
works when path_info is '/' and updated to cross-engine syntax
Mar 31, 2011
e77a4e0
optimized for using ramdisk (but this is probably not the permanent d…
Apr 13, 2011
76abb07
fix assumption that all binary files will be pdf
Apr 13, 2011
f6ed500
support image streaming with "return streamImage()" from resources
Apr 13, 2011
1d8e9c6
example of image streaming without using ramdisk
Apr 13, 2011
5dc8c06
Attempt to format errors in an api-friendly way
Apr 13, 2011
601dcdf
CF 8 compatibility fixes. Replaced script components with <cfcomponen…
bpanulla May 7, 2011
d7d5fe4
Added unit test folder to Taffy's list of excluded paths. Taffy was i…
bpanulla May 11, 2011
8d22214
Fixed CF8 syntactical problems with struct and array literals.
bpanulla May 11, 2011
7d0fdf3
Resolves #33 -- error when attempting to redirect from empty api root…
May 11, 2011
c805191
Resolves #34 - exception in error handling code for duplicate URI pat…
May 11, 2011
de59cc1
99% Resolves #32 -- issues with periods in token values
May 11, 2011
06afa7b
Finalizes resolution for #31 -- error failsafe to show friendly error…
May 11, 2011
30bf1b1
updated tests for recent bug fixes
May 11, 2011
b0dff72
Removed application-level mapping to /taffy. This wasn't needed and w…
bpanulla May 12, 2011
ab84e0b
Stopped stomping on unhandled paths in Application.cfc. Method takes …
bpanulla May 12, 2011
c685ac5
Derived server hostname and port from CGI scope rather than hardcodin…
bpanulla May 12, 2011
45bccef
More hostname/port fixes to let tests work with CF built-in Web server.
bpanulla May 12, 2011
48992e2
Restored default representation class (customJsonRepresentation) in t…
bpanulla May 12, 2011
0c223a7
Sorted the struct keys returned by the service call into alphabetical…
bpanulla May 12, 2011
1f5b84a
Test was failing on CF8 due to key ordering differences in struct imp…
bpanulla May 12, 2011
cbcfdb4
Merged changes by Brian Panulla to make test suite run on older versi…
May 13, 2011
b9fc527
debuggified a few examples
May 13, 2011
643fac3
handle optional mime file extension when there are no tokens
May 13, 2011
8840687
delete non-kitten
May 13, 2011
a4389b8
blah
Jun 10, 2011
435e734
more general handling of encoded request body
Jun 10, 2011
5cb3488
fix parent app example
Jun 10, 2011
c2f0859
fix error where parent-app setup conflicts with auto-dashboard redirect
Jun 10, 2011
1d92216
added test for POST using json request body
Jun 10, 2011
57b2a74
Resolves binary request body issue. Assumes UTF-8 encoding; not sure …
Jun 13, 2011
64a6e4a
Merge branch '1.1-rc' into 1.1-rc-example-updates
Jun 13, 2011
e546f56
fix issues with PUT & POST in general example
Jun 13, 2011
a92e3ec
Make sure there's a bean name to use, and the method isn't just named…
Jun 14, 2011
bfc801e
removed a bunch of useless stuff
Jun 14, 2011
20a0de5
Fixed bugs when using both internal and external factories
Jun 14, 2011
c60b4a6
removing folders from old examples
Jun 14, 2011
f932022
use a relative path lookup for resources that should be compatible wi…
Aug 4, 2011
a68cde8
renamed baseTest to base to prevent it from being used directly as a …
Aug 4, 2011
5cef449
web-runner for tests so you don't have to use eclipse
Aug 4, 2011
9e57fad
not sure how this got out of whack, but there was a bug in mime type …
Aug 4, 2011
ec6d0e3
fix broken tests
Aug 4, 2011
151e59a
tweak framework default mime type usage
Aug 4, 2011
16276d6
remove root mapping for tests
Aug 9, 2011
fdbed7f
update core to fix check for a default mime type
Aug 9, 2011
883fb03
fix URI regex tests
Aug 9, 2011
0fe99ab
restructured input content-type detection to be a bit more robust
Aug 9, 2011
287cd51
since xml input isn't supported out of the box, updated the request-b…
Aug 9, 2011
07f9a76
updated some tests to show more debug info
Aug 9, 2011
6e7358f
better non-json response checking
Aug 12, 2011
fcf1cbc
properly lookup default mime when mime type is given but not supported
Aug 12, 2011
aff16dd
renamed runner.cfm to index.cfm
Aug 17, 2011
f23e20d
refactored tests a bit to be more robust
Aug 17, 2011
cb28caa
cleaned up unhandled path detection and used it to prevent dashboard …
Aug 18, 2011
c5ba187
Added WEB-INF to ignore for Tomcat/Railo installs
Sep 14, 2011
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
.project
.settings
settings.xml
examples/api/jquery-1.4.2.min.js
examples/api/jquery.min.js
WEB-INF
264 changes: 195 additions & 69 deletions core/api.cfc

Large diffs are not rendered by default.

69 changes: 69 additions & 0 deletions core/baseRepresentation.cfc
Original file line number Diff line number Diff line change
@@ -1,11 +1,26 @@
<cfcomponent output="false" hint="a helper class to represent easily serializable data">

<cfset variables.data = "" />
<cfset variables.fileName = "" />
<cfset variables.fileMime = "" />
<cfset variables.statusCode = 200 />
<cfset variables.statusText = "OK" />
<cfset variables.miscHeaders = StructNew() />
<!--- 1= textual, 2= filename, 3= file data --->
<cfset variables.type = 1 />
<cfset variales.types = StructNew() />
<cfset variables.types[1] = "textual" />
<cfset variables.types[2] = "filename" />
<cfset variables.types[3] = "filedata" />
<cfset variables.types[4] = "imagedata" />

<cffunction name="getType" acces="public" output="false">
<cfreturn variables.types[variables.type] />
</cffunction>

<cffunction name="setData" access="public" output="false" hint="setter for the data to be returned">
<cfargument name="data" required="true" hint="the simple or complex data that you want to return to the api consumer" />
<cfset variables.type = 1 />
<cfset variables.data = arguments.data />
<cfreturn this />
</cffunction>
@@ -18,16 +33,70 @@
<cfreturn this />
</cffunction>

<cffunction name="setFileName" access="public" output="false" hint="Pass in a file-name (fully qualified, e.g. c:\temp\img.jpg) to have Taffy stream this file back to the client">
<cfargument name="file" type="string" required="true" />
<cfset variables.type = 2 />
<cfset variables.fileName = file />
<cfreturn this />
</cffunction>

<cffunction name="getFileName" access="public" output="false">
<cfreturn variables.fileName />
</cffunction>

<cffunction name="setFileData" access="public" output="false" hint="Pass in file data (eg a generated PDF object) - NOT a Filename! - to have Taffy stream the content back to the client">
<cfargument name="data" required="true" />
<cfset variables.type = 3 />
<cfset variables.fileData = data />
<cfreturn this />
</cffunction>

<cffunction name="getFileData" access="public" output="false">
<cfreturn variables.fileData />
</cffunction>

<cffunction name="setImageData" access="public" output="false" hint="Pass in image data (eg a generated image object) - NOT a Filename! - to have Taffy stream the content back to the client">
<cfargument name="data" required="true" />
<cfset variables.type = 4 />
<cfif not isBinary(arguments.data)>
<cfset data = toBinary(toBase64(arguments.data)) />
</cfif>
<cfset variables.fileData = data />
<cfreturn this />
</cffunction>

<cffunction name="getImageData" access="public" output="false">
<cfreturn getFileData() />
</cffunction>

<cffunction name="withMime" access="public" output="false" hint="Use this method in conjunction with streamFile and streamBinary in your resources to set the mime type of the file being returned. Ex: return streamFile('kittens/cuteness.jpg').withMime('image/jpeg');">
<cfargument name="mime" type="string" required="true" />
<cfset variables.fileMime = arguments.mime />
<cfreturn this />
</cffunction>

<cffunction name="getFileMime" access="public" output="false">
<cfreturn variables.fileMime />
</cffunction>

<cffunction name="withStatus" access="public" output="false" hint="used to set the http response code for the response">
<cfargument name="statusCode" type="numeric" required="true" hint="eg 200" />
<cfargument name="statusText" type="string" required="false" default="" />
<cfset variables.statusCode = arguments.statusCode />
<cfif len(arguments.statusText)>
<cfset variables.statusText = arguments.statusText />
</cfif>
<cfreturn this />
</cffunction>

<cffunction name="getStatus" access="public" output="false" returnType="numeric">
<cfreturn variables.statusCode />
</cffunction>

<cffunction name="getStatusText" access="public" output="false" returnType="string">
<cfreturn variables.statusText />
</cffunction>

<cffunction name="withHeaders" access="public" output="false" hint="used to set custom headers for the response">
<cfargument name="headerStruct" type="struct" required="true" />
<cfset variables.miscHeaders = arguments.headerStruct />
3 changes: 2 additions & 1 deletion core/factory.cfc
Original file line number Diff line number Diff line change
@@ -26,6 +26,7 @@
</cfscript>
<cffunction name="loadBeansFromPath" access="public" output="false" returnType="void">
<cfargument name="beanPath" type="string" required="true" hint="Absolute path to folder containing beans" />
<cfargument name="resourcesPath" type="string" default="resources" />
<cfset var local = StructNew() />
<!--- if the folder doesn't exist, do nothing --->
<cfif not directoryExists(arguments.beanPath)>
@@ -36,7 +37,7 @@
<!--- cache all of the beans --->
<cfloop query="local.beanQuery">
<cfset local.beanName = left(local.beanQuery.name, len(local.beanQuery.name)-4) /><!--- drop the ".cfc" --->
<cfset this.beans[local.beanName] = createObject("component", "resources." & local.beanName) />
<cfset this.beans[local.beanName] = createObject("component", arguments.resourcesPath & "." & local.beanName) />
</cfloop>
<!--- resolve dependencies --->
<cfloop list="#structKeyList(this.beans)#" index="local.b">
12 changes: 6 additions & 6 deletions core/mocker.cfm
Original file line number Diff line number Diff line change
@@ -45,11 +45,16 @@
function submitRequest( verb, resource, representation ){
var endpoint = 'http://<cfoutput>#cgi.server_name#<cfif cgi.SERVER_PORT neq 80>:#cgi.SERVER_PORT#</cfif>#cgi.SCRIPT_NAME#</cfoutput>';
var url = endpoint + resource;
var dType = null;
if (representation && representation.indexOf("{") == 0){
dType = "application/json";
}
$("#rest_body").hide();
$.ajax({
type: verb,
url: url,
data: representation,
contentType: dType,
success: function(data, status, xhr){
$("#headers").val(xhr.getAllResponseHeaders());
$("#statuscode").val(xhr.status + " " + xhr.statusText).removeClass("statusError").addClass("statusSuccess");
@@ -78,12 +83,7 @@
submitRequest("DELETE", $("#uri").val(), null);
});
$("#submit_post").click(function(){
//Seems like POST requests can't accept a JSON packet as the data attribute, so let's first convert it to a query string
var data = $("#content").val();
try {
data = $.param($.parseJSON(data));
} catch (e) {}
submitRequest("POST", $("#uri").val(), data);
submitRequest("POST", $("#uri").val(), $("#content").val());
});
});
</script>
32 changes: 24 additions & 8 deletions core/resource.cfc
Original file line number Diff line number Diff line change
@@ -4,27 +4,43 @@
<cffunction name="representationOf" access="private" output="false" hint="returns an object capable of serializing the data in a variety of formats">
<cfargument name="data" required="true" hint="any simple or complex data that should be returned for the request" />
<cfargument name="customRepresentationClass" type="string" required="false" default="" hint="pass in the dot.notation.cfc.path for your custom representation object" />

<cfif arguments.customRepresentationClass eq "">
<cfreturn getRepInstance(application._taffy.settings.defaultRepresentationClass).setData(arguments.data) />
<cfelse>
<cfreturn getRepInstance(arguments.customRepresentationClass).setData(arguments.data) />
</cfif>

<cfreturn getRepInstance(arguments.customRepresentationClass).setData(arguments.data) />
</cffunction>

<cffunction name="noData" access="private" output="false" hint="use this function to return only headers to the consumer, no data">
<cfreturn createObject("component", application._taffy.settings.defaultRepresentationClass).noData() />
</cffunction>

<cffunction name="streamFile" access="private" output="false" hint="Use this function to specify a file name (eg c:\tmp\kitten.jpg) to be streamed to the client. When you use this method it is *required* that you also use .withMime() to specify the mime type.">
<cfargument name="fileName" required="true" hint="fully qualified file path (eg c:\tmp\kitten.jpg)" />
<cfargument name="customRepresentationClass" type="string" required="false" default="" hint="pass in the dot.notation.cfc.path for your custom representation object" />
<cfreturn getRepInstance(arguments.customRepresentationClass).setFileName(arguments.fileName) />
</cffunction>

<cffunction name="streamBinary" access="private" output="false" hint="Use this function to stream binary data, like a generated PDF object, to the client. When you use this method it is *required* that you also use .withMime() to specify the mime type.">
<cfargument name="binaryData" required="true" hint="binary file data (eg a PDF object) that you want to return to the client" />
<cfargument name="customRepresentationClass" type="string" required="false" default="" hint="pass in the dot.notation.cfc.path for your custom representation object" />
<cfreturn getRepInstance(arguments.customRepresentationClass).setFileData(arguments.binaryData) />
</cffunction>

<cffunction name="streamImage" access="private" output="false" hint="Use this function to stream binary data, like a generated PDF object, to the client. When you use this method it is *required* that you also use .withMime() to specify the mime type.">
<cfargument name="binaryData" required="true" hint="binary file data (eg a PDF object or image data) that you want to return to the client" />
<cfargument name="customRepresentationClass" type="string" required="false" default="" hint="pass in the dot.notation.cfc.path for your custom representation object" />
<cfreturn getRepInstance(arguments.customRepresentationClass).setImageData(arguments.binaryData) />
</cffunction>

<!---
function that gets the representation class instance
-- if the argument is blank, we use the default from taffy settings
-- if the argument is a beanName, the bean is returned from the factory;
-- otherwise it is assumed to be a cfc path and that cfc instance is returned
--->
<cffunction name="getRepInstance" access="private" output="false">
<cfargument name="repClass" type="string" />
<cfif application._taffy.factory.containsBean(arguments.repClass)>
<cfif repClass eq "">
<!--- recursion not the most efficient path here, but it's damn readable --->
<cfreturn getRepInstance(application._taffy.settings.defaultRepresentationClass) />
<cfelseif application._taffy.factory.containsBean(arguments.repClass)>
<cfreturn application._taffy.factory.getBean(arguments.repClass) />
<cfelse>
<cfreturn createObject("component", arguments.repClass) />
14 changes: 8 additions & 6 deletions examples/ParentApplication/Application.cfc
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
<cfcomponent output="false">

<cfscript>
this.name = "taffy_ParentAppExample";
this.name = "taffy_ParentAppExample";//same name as parent folder application.cfc
this.applicationTimeout = createTimeSpan(0,2,0,0);
this.sessionManagement = false;
this.setClientCookies = true;
this.setClientCookies = false;
this.scriptProtect = false;
</cfscript>

@@ -13,17 +13,19 @@
<cfset application.beanFactory = createObject("component", "coldspring.beans.DefaultXMLBeanFactory") />
<cfset application.beanFactory.loadBeans('/taffy/examples/ParentApplication/config/coldspring.xml') />

<cfparam name="application.init" default="#structNew()#" />
<cfset application.init.app = true />
<cfparam name="application.parentInit" default="true" />

<cfreturn true />
</cffunction>

<cffunction name="onRequestStart" returnType="boolean" output="false">
<cfargument name="thePage" type="string" required="true" />

<cfif not structKeyExists(application, "init") or not structKeyExists(application.init, "app")>
<cfset onApplicationStart() />
<!--- if the PARENT application has not been initialized, or if user is requesting reinit... --->
<cfif
not structKeyExists(application, "parentInit")
or structKeyExists(url, "reinit")>
<cfset onApplicationStart() />
</cfif>

<cfreturn true />
6 changes: 6 additions & 0 deletions examples/ParentApplication/api/.htaccess
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
RewriteEngine On

#if we've already been rewritten to use index.cfm/* format, don't make a circular request
RewriteRule index\.cfm/* - [L]

RewriteRule ^(.*)$ index.cfm/$1
30 changes: 6 additions & 24 deletions examples/ParentApplication/api/Application.cfc
Original file line number Diff line number Diff line change
@@ -1,47 +1,29 @@
component extends="taffy.core.api" {

this.name = "taffy_ParentAppExample";
this.name = "taffy_ParentAppExample";//same name as api folder application.cfc

//do your onApplicationStart stuff here
function applicationStartEvent(){
application.beanFactory = createObject("component", "coldspring.beans.DefaultXMLBeanFactory");
application.beanFactory.loadBeans('/taffy/examples/ParentApplication/config/coldspring.xml');

param name="application.init" default="#structNew()#";
application.init.api = true;
if (!structKeyExists(application, "beanFactory")){
application.beanFactory = createObject("component", "coldspring.beans.DefaultXMLBeanFactory");
application.beanFactory.loadBeans('/taffy/examples/ParentApplication/config/coldspring.xml');
}
}

//do your onRequestStart stuff here
function requestStartEvent(){
if (!structKeyExists(application, "init") || !structKeyExists(application.init, "api")){
if ( !structKeyExists(application, "_taffy") ){
onApplicationStart();
}
}

//this function is called after the request has been parsed and all request details are known
function onTaffyRequest(string verb, string cfc, struct requestArguments, string mimeExt){
//this would be a good place for you to check API key validity and other non-resource-specific validation
return true;
}

//called when taffy is initializing or when a reload is requested
void function configureTaffy(){

setBeanFactory(application.beanfactory);
setDebugKey("debug");
setReloadKey("reload");
setReloadPassword("true");

//you could change this to a custom class to change the default instead of specifying an override for each response
setDefaultRepresentationClass("taffy.core.genericRepresentation");

//tell Taffy about the parent application's bean factory, which we have access to because
//we're using the same application name
setBeanFactory(application.beanFactory);

//these are both the default settings, but the functions are used here to illustrate how and where you should use them
registerMimeType("json", "application/json");
setDefaultMime("json");
}

}
2 changes: 1 addition & 1 deletion examples/ParentApplication/config/coldspring.xml
Original file line number Diff line number Diff line change
@@ -3,7 +3,7 @@

<bean id="fakeData" class="taffy.examples.shared.fakeData" />

<bean id="artfartCollection" class="taffy.examples.ParentApplication.model.artfartCollection">
<bean id="fooCollection" class="taffy.examples.ParentApplication.model.fooCollection">
<property name="fakeData">
<ref bean="fakeData" />
</property>
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<cfcomponent extends="taffy.core.resource" taffy_uri="/artfarts">
<cfcomponent extends="taffy.core.resource" taffy_uri="/foo">

<cffunction name="get" access="public" output="false">
<cfreturn representationOf(variables.fakeData.getData()).withStatus(200) />
6 changes: 6 additions & 0 deletions examples/api/.htaccess
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
RewriteEngine On

#if we've already been rewritten to use index.cfm/* format, don't make a circular request
RewriteRule index\.cfm/* - [L]

RewriteRule ^(.*)$ index.cfm/$1
6 changes: 6 additions & 0 deletions examples/api_anythingtoxml/.htaccess
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
RewriteEngine On

#if we've already been rewritten to use index.cfm/* format, don't make a circular request
RewriteRule index\.cfm/* - [L]

RewriteRule ^(.*)$ index.cfm/$1
31 changes: 0 additions & 31 deletions examples/api_both/Application.cfc

This file was deleted.

2 changes: 1 addition & 1 deletion examples/api_coldspring/Application.cfc
Original file line number Diff line number Diff line change
@@ -5,7 +5,7 @@
//do your onApplicationStart stuff here
function applicationStartEvent(){
application.beanFactory = createObject("component", "coldspring.beans.DefaultXMLBeanFactory");
application.beanFactory.loadBeans('config/coldspring.xml');
application.beanFactory.loadBeans('/taffy/examples/api_coldspring/config/coldspring.xml');
}

//do your onRequestStart stuff here
4 changes: 2 additions & 2 deletions examples/api_coldspring/config/coldspring.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<beans default-autowire="byName">

<bean id="fakeData" class="taffy.examples.shared.fakeData" />
<bean id="artfartCollection" class="taffy.examples.api_coldspring.stuff.artfartCollection" autowire="byname" />
<bean id="artfartCollection" class="taffy.examples.api_coldspring.stuff.artfartCollection" />

</beans>
6 changes: 6 additions & 0 deletions examples/api_img/.htaccess
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
RewriteEngine On

#if we've already been rewritten to use index.cfm/* format, don't make a circular request
RewriteRule ^(index\.cfm[/.]?+|images/.*) - [L]

RewriteRule ^(.*)$ index.cfm/$1
Loading