REST Web Service 404 Not found - ColdFusion 11 - coldfusion

I created a new function in an existing REST cfc but when I am trying to call it I receive a 404 Error where the rest of the functions are working. All of the functions are following the same structure as the one I am about to link further down without any issues.
I saw another post like mine but I didn't find any answers in it. This is the link for the other post here
<cfcomponent restpath="student" rest="true">
<cffunction name="npssummary" access="remote" output="false" returntype="any" httpmethod="get" restpath="npssummary" produces="application/json">
<cfquery name="nps_summary" datasource="dpsigweb2">
select top 10 * from contact
</cfquery>
<cfreturn serializeJSON(nps_summary,"struct")>
</cffunction>
</cfcomponent>
And this is how I am calling it
<cfhttp url="http://dev.example.com/rest/IIT/student/npssummary" method="get">
<cfset results = "#cfhttp#">
<cfdump var="#results#">
When I am trying to call the function directly in the browser I receive the expected result.
Also, I am using this function to reset the REST services each time I make a change to my component it seems to be working as expected so far.
<cftry>
<cfset restInitApplication("Z:\Sites\testSites\API\","IIT")>
<cfcatch type="any">
<cfdump var="#cfcatch#">
</cfcatch>
</cftry>

This is a browser limitation:
Microsoft Internet Explorer has a maximum uniform resource locator (URL) length of 2,083 characters. Internet Explorer also has a maximum path length of 2,048 characters. This limit applies to both POST request and GET request URLs.
If you are using the GET method, you are limited to a maximum of 2,048 characters, minus the number of characters in the actual path.
However, the POST method is not limited by the size of the URL for submitting name/value pairs. These pairs are transferred in the header and not in the URL.
RFC 2616, "Hypertext Transfer Protocol -- HTTP/1.1," does not specify any requirement for URL length.

Related

Taffy framework not accepting period "." in URL

When receiving values in a url with a period ".", somehow Taffy doesn't like it and doesn't show results. For example:
Endpoint URL:
mydomain.com/v1/devices/f15566dc799casdfc0b042642casdf7b1/registrations/pa.com.cnn.com
CFComponent:
<cfcomponent extends="taffy.core.resource"
taffy:uri="/v1/devices/{deviceid}/registrations/{registrationid}" >
<cffunction name="get" access="public" output="false" >
<cfset var retCode = 200>
<cfreturn representationOf("/v1/devices/#arguments.deviceid#/registrations/#arguments.registrationid#").withStatus(retCode) />
</cffunction>
</cfcomponent>
When I remove the periods, for example:
Endpoint URL:
mydomain.com/v1/devices/f15566dc799casdfc0b042642casdf7b1/registrations/pacomcnncom
Results:
"/v1/devices/f15566dc799casdfc0b042642casdf7b1/registrations/pacomcnncom"
A bit late but I assume you're using Taffy.
Taffy, because it parses for file extensions to set mime-types of its responses, cannot have extraneous 'dots' in the URI. There are workarounds apparently . . .
You can use regex to refine the taffy_uri.
https://github.com/atuttle/Taffy/wiki/Custom-token-regular-expressions
I've tried this but not had success, opting to not have an end point requiring valid email address on the URI. Instead, posting the email address in the POST body.
More info here
https://groups.google.com/forum/#!msg/taffy-users/HbYCeCvuTLA/1-eco35pAwAJ;context-place=forum/taffy-users
B.

Exempting Coldfusion page from authentication

I need to post from a non-secure CF page to a secure CF page. I don't want to have to go through and implement the user authentication on the page sending the values because its a rather cumbersome process due to the way this legacy site was setup and secondly because the page sending the values is acting as a service between two unrelated order management systems as opposed to a user.
Right now, when I try to post to, the response result is a redirect to the login of the homepage. Is there a way to make an exception for a posting or receiving page from forcing user authentication?
I'm using <cfhttp> to post the values to post page which has a series of <cfparam>'s that I'm passing the values to. Once I pass those values into the post page is when the post page triggers a redirect to the home page because the post page is an internal page in the order management system and is displayed as a client logs in and a session is created for them.
Since you did not provide any code, here is a guess what it might look like and how you could add an exception for specific requests:
<cffunction name="onRequestStart" access="public" output="false" returnType="boolean">
<cfargument name="targetPage" type="string" required="true">
<!--- treat initialized SESSION or matching request token (rtoken) as successful authentication --->
<cfset LOCAL.isAuthenticated = (
isDefined("SESSION.userID")
or
( structKeyExists(FORM, "rtoken") and (FORM["rtoken"] eq "some-secret-only-you-know") )
)>
<cfif LOCAL.isAuthenticated>
<!--- do something... --->
<!--- not authenticated --->
<cfelse>
<!--- redirect to login --->
<cflocation url="login.cfm" statusCode="303" addToken="false">
</cfif>
</cffunction>
Now you could simple add the key-value-pair rtoken=some-secret-only-you-know (i.e. <input type="hidden" name="rtoken" value="some-secret-only-you-know" />) to your POST to bypass the session based authentification.
Disclaimer: Only use this method if the POST parameters (form fields) are not public/editable by the user.
Feel free to provide actual context so I can assist in a more concrete way.
I have written a couple of apps with similar, but not identical requirements. Here is how I handled those requirements in the last one I wrote. All this code is the Application.cfc file in the methods specified.
In onApplicationStart:
application.securityNotNeededPages =
"somePage.cfm,someOtherPage.cfm,someMorePages.cfm";
In onRequestStart
var ThisPage = listlast(cgi.PATH_INFO, "/");
...
if (ListFindNoCase(application.securityNotNeededPages, ThisPage) is false) {
security related code
}
else {
code for when the page does not to be secured
}

File Not Found in CF11 even though file exists

Well, I have been experiencing same error as discussed here:
Coldfusion 10 File Not Found Error
I am using Coldfusion 11 , developer edition on my Laptop , Windows 8.1 Pro (OS).
People have suggested two approaches over there to overcome this problem:
1) Setting Missing Template in CFAdmin
2) Setup onMissingTemplate function in Application.cfc
I am basically not sure with any of the approaches , however, I would like to go with the first approach. Could anyone tell me how should I set up missing template in CFadmin?
Why do you prefer letting the server handle the missing template? Myself, I like to handle it on a per-application basis. Some applications should never have links leading to non-existing files, others may operate on that as part of its core.
Straight from adobe's docs, you can use (I accidentally pulled this info from cf8 docs, but the link is to current docs and the result is largely the same.
<cffunction name="onMissingTemplate" returnType="boolean">
<cfargument type="string" name="targetPage" required=true/>
...
<cfreturn BooleanValue />
</cffunction>
For a few of my projects, I've written a CMS (Content-Management-System) that stores all the content in the database in fashion.
CMSPages
------------
PID PTitle PFile PContent
1 Home /index.cfm <b>Hey!</b> Welcome to our gollygizmo website.
And then I (my real code actually uses cfincludes rather than directly in the document. You can do it either way, but it was easiest for me to demonstrate with inline code).
<cffunction name="onMissingTemplate" returnType="boolean">
<cfargument type="string" name="targetPage" required=true/>
<cftry>
<cfquery name="FindPage">
select * from CMSPages
where pFile = <cfqueryparam cfsqltype="nvarchar" value="#Arguments.targetPage#">
</cfquery>
<cfif FindPage.recordcount eq 1>
<cfoutput query="FindPage">show page stuffs</cfoutput>
<cfreturn true>
<cfelse>
<!--- Page not found, log some stuff or email stuff
include cgi data so you know where the link came from --->
Hey, this page doesn't exist, sorry about that.
<cfreturn true>
</cfif>
<cfcatch>
<!--- Something went wrong, log/email error info and --->
<cfreturn false>
<!--- We return false here to pass it back to the default error handler, which can be a handler set in cfadmin. --->
</cfcatch>
</cftry>
</cffunction>
In such a scenario, it's probably beneficial to cache queries based on query name, you can do something like
<cfquery name="local.FindPage#hash(arguments.targetpage)#" cachedWithin="...">
...
</cfquery>
<cfset request.FindPage=local["Findpage#hash(arguments.targetpage)#"]>
So that the queries are cached by unique names, even though it's easily accesible in your document by a common name.
However, if you still prefer server-centric missing template handling, a simple search for cold fusion admin missing template will bring you here.
In the ColdFusion Administrator, click on "Settings" to view the "Server Settings" page
Specify the absolute path that ColdFusion will use to find your error handling template

onRequestStart user authorisation does not work correctly coldfusion

Im my Application.cfc I am trying to use the onRequestStart() function to protect my pages as such:
<cffunction name="onRequestStart" access="public" returntype="boolean">
<cfargument type="String" name="TargetPage" required="true"/>
<!--- Define which pages don't need protection --->
<cfset APPLICATION.AllowedPages = "/index.cfm, /register.cfm">
<!--- Create an instance of the page-protect.cfc --->
<cfset APPLICATION.PageProtect = CreateObject("component", "page-protect")>
<!--- check if the current page is an allowed page --->
<cfif #ListFindNoCase(APPLICATION.AllowedPages, ARGUMENTS.TargetPage)# EQ 0>
<!--- if its not an allowed page, then protect it --->
<cfscript>
APPLICATION.PageProtect.PageProtectBasic(argumentcollection = session);
</cfscript>
</cfif>
<cfreturn true>
</cffunction>
This code works (kind of as you will see later). Page-protect.cfc is very simple and does this:
<cfcomponent displayname="page-protect" output="false">
<cffunction name="PageProtectBasic" output="no">
<cfif NOT structKeyExists (SESSION, 'Auth')>
<cflocation url="/index.cfm" addtoken="no">
</cfif>
</cffunction>
</cfcomponent>
So if the Auth structure within the SESSION scope does not exist, then this user is not logged in and should be taken back the homepage. A logout method in a different file deletes the Auth structure from SESSION and also clears the SESSION scope (if definitely does this I have tested it).
The onRequestStart() page protection works initially but I have noticed that when I press the back button on my browser it will show the previous page that I just logged out of. This should be a protected page and not display but I guess its a browser cache so not a problem. However the problem is that if I click on a link in this page it SHOULD not allow it and send the user back to home page (because the SESSION.Auth structure does not exist and SESSION has been cleared). But it does not send the user back to the homepage anymore, it just shows a ColdFusion error page stating that "Element AUTH.{element_name} is undefined in SESSION".
So for some reason its not going back to the homepage despite the user not being logged in, and instead is trying to load the protected page and then falling over because a variable within the SESSION.AUTH structure does not exist. I simply don't understand what I'm doing wrong. Please help!
While James Mohler provides some very helpful pointers on how to improve your code in general the issue you are having is not related to that.
The reason that users can see these pages on hitting back is because they are cached in the browser. This is the browser trying to be helpful and not requesting data from the server that it has already seen. The browser being a good internet citizen will do what it is told though. So you need to return the correct HTTP headers to tell it that you don't want it to cache them. E.g.
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
So to do this in CF
<cfheader name="Cache-Control" value="no-cache, no-store, max-age=0, must-revalidate">
<cfheader name="Pragma" value="no-cache">
If you add the above to the pages that are concerning you, the problem will go away.
Simon
Sorry, this won't fit into a comment box
I think what you are trying to do is something like this:
onApplicationStart() {
APPLICATION.PageProtect = CreateObject("component", "page-protect")>
}
onSessionStart() {
session.auth = false; // it is easier to work with if it always exists
}
onRequestStart() {
if (ListFindNoCase(APPLICATION.AllowedPages, ARGUMENTS.TargetPage) EQ 0)
// if its not an allowed page, then protect it
APPLICATION.PageProtect.PageProtectBasic(argumentcollection = session);
}
}
Possibly not related to your problem but this line might have a couple of issues.
<cfset APPLICATION.AllowedPages = "/index.cfm, /register.cfm">
Issue number 1 is the leading slashes. Unless arguments.TargetPage has those slashes, and they might, you are not going to get the expected behaviour.
Issue number 2 is the space between your two list items. Leading spaces are part of the list item which could lead to unexpected behaviour on register.cfm.

ColdFusion onSessionEnd problem

I have read many posts by people who have problems with onSessionEnd. This is my first conversion of application.cfm to application.cfc and the onSessionEnd is not working with the CFFunction I am trying to invoke.
I guess what's hanging this up is how to properly call the component from the /lib/components/ folder where it resides.
When a user logs in I am creating a session array that tracks a jobNumber and the last_completed_step in that job. There are multiple jobs in a users session. At the end of the session I want to write the updated array data back to the DB.
I should make it clear that at present I look into my log file and see that the session is started - as coded in the onSessionStart shown below. Furthermore, the onSessionEnd also writes to the log file when I take out the invocation of the component. In other words if I just tell it to write "Session ended." to the log file I will see it in the log file. I have set current session timeout in CF Administrator and my app.cfc for 3 minutes for testing.
If I call the "giveMeAnswer" method in the jobState.cfc from a separate file (also at the root level) the giveMeAnswer method works properly and returns the value "I am a CFC."
If I move the jobState.cfc to the root level and set the component attribute to "jobState" I am also getting a return from the component.
<!--- Runs when your session starts --->
<cffunction name="onSessionStart" returnType="void" output="false">
<!--- :: invoke all session variables | moved out of on session start :: --->
<cfinvoke component="#application.virtualPaths.cfcPath#system/sessionVars" method="init" />
<cflog file="#This.Name#" type="Information" text="Session started.">
</cffunction>
<!--- Runs when session times out --->
<cffunction name="onSessionEnd" returntype="void">
<cfargument name="SessionScope" type="struct" required="true" />
<cfargument name="ApplicationScope" type="struct" required="true" />
<cfinvoke component="/lib/components/jobState" method="giveMeAnswer" returnvariable="returnFromCfc">
</cfinvoke>
<cflog file="#This.Name#" type="Information" text="Session ended. #returnFromCfc#">
<cfreturn />
</cffunction>
So, is it just not finding the component? Any other ideas?
Thanks much, Jerry
I know I've seen folks use / in component calls before, but I do not believe it is officially supported. You want to use a dot notation path instead, ala
component="lib.components.jobstate"
and assure that lib is either a subdirectory or a known CF mapping that points to the lib folder.