I am using cfhttp to get documents and parse the content like so:
<cfhttp
method="GET"
url="#url.strURL#"
resolveurl="true"
useragent="#CGI.http_user_agent#"
result="objGet"
timeout="60"
charset="utf-8"
/>
However, some of the documents are rather large. I do not need to get the entire thing - which could take a long time.
Is there any way in which I can stop running cfhttp after X number of bytes loaded? Or set a limit on how much to get for example.
Appreciate the help.
If the target server supports it, you can use the Range http header:
<cfhttp
method="GET"
url="#url.strURL#"
resolveurl="true"
useragent="#CGI.http_user_agent#"
result="objGet"
timeout="60"
charset="utf-8"/>
<cfhttpparam type="header" name="Range" value="bytes=0-499" />
</cfhttp>
Apache and IIS supports this, so for static content you'll probably be in luck. Dynamic content would be trickier...
...I've just tried this with a CFM being served through Apache, and it looks like that didn't work. I suspect that if Apache/IIS is serving a static file, then it can safely send back a range of bytes from the document you're requesting because it can read the file. If the request is for something being generated by CF/ASP/JSP/whatever, then it'd be up to the Appliation to honour the Range: header in the request. In my case, I still got the whole document because my Application doesn't look at the Range header.
I should also mention that it's possible to do what you're after in Java, as you've got finer-level control of what's going on, but you'd have to write something yourself or use one of the alternative HTTP Client Libraries out there. It depends how important the feature is to you I suppose. If the documents are seriously large then you may need to use the file attribute of cfhttp to avoid getting the whole response into memory, which could cause crashes.
Related
In my Application.cfc, I setup a mapping
this.mappings["/downloads"]="J:\Downloads\documents";
In my template, I have
<cfdirectory action="list" directory="#expandpath("/downloads")#" filter="*.zip|*.docx" name="downloads" recurse="yes">
<!--- <cfdump var="#expandpath("/software")#"> --->
<cfdump var="#downloads#">
<ul>
<cfoutput query="#downloads#">
<li>#downloads.name#</li>
</cfoutput>
</ul>
I'm trying to make the documents downloadable but when the link is clicked, nothing is happening which makes me think my links are not correct however when I mouse over the link, I see the full path which is correct.
What am I missing to make the list of documents clickable?
Here is the URL displayed when mouseover the 3rd document for example.
Since the files are outside of your webroot you will need to have ColdFusion read the file and send it back to the browser.
You will need to create a page, like download.cfm, that can accept a URL parameter to know which file to access. Once you have selected the file you can use something like the following to stream the file.
<cfheader name="Content-disposition" value="attachment;filename=#datafile#">
<cfcontent file="#datafile#" type="application/pdf">
The above code was pulled from https://www.raymondcamden.com/2006/03/10/Ask-a-Jedi-Using-ColdFusion-to-serve-files
WARNING:
Reading URL parameters in this way and giving people access to the filesystem is extremely unsafe. Safer alternatives should be considered before moving something like this into a production environment.
All I needed to do for this exercise is to setup a mapping in my Application.cfc. As others have stated, there is zero security here but for the purpose of this exercise of understanding virtual directories (IIS) and aliases (CommandBox), this is sufficient.
this.mappings["/guides"]="J:\guides";
Then I can use cfdirectory to build my query object
<cfdirectory action="list" directory="j:\guides" recurse="false" name="nameofqry" type="file" sort="datelastmodified desc" filter="*.docx">
Next, perform a cfoutput using my alias as the a href link
<cfoutput query="nameofqry" maxrows="40">
<li>#nameofqry.name#</li>
</cfoutput>
Update: reported bug, votes appreciated https://tracker.adobe.com/#/view/CF-4200017
We are migrating from ColdFusion 10 to 2016. It appears the only hurdle with compatibility is the change in charting system. For full page requests this is generally fine but in some spots we generate a chart in png format, capture the content generated and strip out some js that is generated simultaneously and return the result in json as part of a page update. A problem we are running into is that CF is forcing javascript in the request response separate from the actual content being output causing json responses to be invalid.
It seems the js is being inserted using an approach like the cfhtmlhead tag where it looks in the response for head tags, inserts code there if found, otherwise it just prepends the code to the entire request. For a response that should be json this is obviously a problem.
I already tried calling a flush before the chart generates but then I get the error "ColdFusion was unable to add the text you specified to the output stream. This is probably because you have already used a CFFLUSH tag in your template or buffered output is turned off" when the cfchart code is hit.
Any suggestions on how to tell CF to put the code inline or otherwise reset the content planned for insertion into the request output?
Example:
<cfsavecontent variable="ignore">
<cfchart format="png">
<cfchartseries type="Bar" label="Numbers">
<cfchartdata item="First" value="1">
<cfchartdata item="Second" value="2">
</cfchartseries>
</cfchart>
</cfsavecontent>
<cfcontent reset="true" />
test
Result:
<script type="text/javascript">/* <![CDATA[ */_cf_loadingtexthtml="<img alt=' ' src='/cf_scripts/scripts/ajax/resources/cf/images/loading.gif'/>";
_cf_contextpath="";
_cf_ajaxscriptsrc="/cf_scripts/scripts/ajax";
_cf_jsonprefix='//';
_cf_websocket_port=8579;
_cf_flash_policy_port=1243;
_cf_clientid='1D0DA2C606EC323ABBECA5B29A016CF0';/* ]]> */</script><script type="text/javascript" src="/cf_scripts/scripts/ajax/messages/cfmessage.js"></script>
<script type="text/javascript" src="/cf_scripts/scripts/ajax/package/cfajax.js"></script>
<script type="text/javascript" src="/cf_scripts/scripts/chart/cfchart-server.js"></script>
test
It is even an issue for charts used in cfdocument tags (just replace the cfsavecontent tags with cfdocument filename="test.pdf" to test). The chart gets added to the document on disk but then js gets output in the request response, killing our ajax requests that are meant to bring back the download link and other data.
Found a workaround which is to to perform the chart generation in a thread. The output is then only the base chart content and not head content.
This can be addressed with either of the following options for resetting the content that CF inserts automatically into the <head>:
<cfcontent reset="true" resethead="true">
or
<cfset getPageContext().getCFOutput().clearHeaderBuffers()>
These approaches are not documented (so possible to change in future version -- though unlikely) and these approaches are unlikely to be portable to other CFML engines.
I’ve run into a seemingly particular problem that I’ve been unable to figure out thus far.
I’ve gzipped a bunch of the static CSS and JavaScript files on our website for the client’s browser to consume. I am using a ColdFusion page to check the Accept-Encoding to determine if the browser says it can inflate the .gz files. If it cannot I send the regular .css or .js file.
After implementing this process I tested it on both my local and our dev environment with no issue in all major browsers with no problems. However, in our production environment only, Safari and IE cannot seem to inflate the gzipped files despite indicating they can when I check the Accept-Encoding.
Here is a snip of what Safari reads the file as:
¬� !T
common.css�}k��F��� �?�,4��#� �(�
�8{�� ���־� n %�JܖD-IuuY��~�Έ��$Um/p���.�̌�|E�;7���z����t�>��ݮ<=�o�թ =����r�}]��a��E��O�0�Sq�\���}m�S3j��||�V���-�i�:ز�ũ]��yyj�D�_����ܵ���"=y ���d�Ku��U����;�"[7�u]>�[��b���<< ���? �-]z�JOAi�� �� �� lPxJ bAOx�Mն�Q�Oƛꋪ�-S� � �~?��Q �,�� m��aw�5S�i��8�>
�G ���ݫ.��(h�Q O>�_wes>�/�'��u�¬6Nى�K�F"y�]
T1 fE� ¬�Į>
On all three servers are Windows machines, running ColdFusion 10 on tomcat. We are using IIS 7.5 on all servers as well.
After a lot of research last week, I’m no closer to an explanation/solution.
What I’ve read on the net as indicated that the “Transfer-Encoding: chunked” could be a problem. I can see it listed in the response headers of IE (Safari lists it as Transfer-Encoding: Identity) and this header only appears there when looking at the production environment as well.
In relation to the Transfer-Encoding, when it is not present (local and dev) the Content-Length header comes through where it is not present when the “Transfer-Encoding: chunked” is there.
Also I can confirm that Static compression is enabled in IIS for the site in all three environments.
Many people have recommended disabling chunked Transfer-Encoding via the ASP portion of IIS and while we could do this, I’m not sure if it’s a good idea?
ASP is NOT installed on our production environment and our Sys Admin is understandably wary of installing it (so it appears in IIS) when we do not write anything in ASP.
I have also read about forcing http/1.0 rather than allowing http/1.1 but this seems like a cop-out and a rather inefficient one at that.
But is that our only option? And if so, is it worth it? Am I even going about this is the correct fashion? I wanted to pre-compile the .gz files to eliminate any unneeded processing on our production server.
I’m not sure what other information I could provide to be helpful but I can gladly ass more info to this post if needed.
Example of .cfm that loads the CSS:
<cfparam name="URL.name" default="" />
<cfif Len( URL['name'] ) GT 0 AND Len( url.name ) LT 64 AND ReFind( url.name, "[^a-zA-Z\-\.\_]+" ) EQ 0>
<cfif CGI['http_accept_encoding'] CONTAINS "gzip" AND FileExists( ExpandPath( './css/' & url.name & '.gz' ) )>
<cfheader name="Content-Encoding" value="gzip" />
<cfcontent reset="true" type="text/css" deletefile="no" file="#ExpandPath('./css/#url.name#.gz')#" />
<cfelseif FileExists( ExpandPath( './css/#url.name#.css' ) )>
<cfcontent reset="true" type="text/css" deletefile="no" file="#ExpandPath('./css/#url.name#.css')#" />
</cfif>
</cfif>
<cfabort>
I have been tasked with researching the possibility of storing .cfm files outside of the web root as a further security measure. (I'm not talking about CFCs, but the files that will appear in the URL string.)
I figured that I could use the properties of OnRequest() in the Application.cfc to do this, but no luck.
I've tried this:
<cffunction name="OnRequest" access="public" returntype="void" output="true">
<cfargument name="TargetPage" type="string" required="true"/>
<cfinclude template="C:/test#arguments.TargetPage#"/>
<cfreturn/>
</cffunction>
I then put a test.cfm inside C:\test and attempted http://localhost/test.cfm. That gives me a "file not found" error.
So then I created a ColdFusion mapping to C:\test called "test" and changed my CFINCLUDE thusly:
<cfinclude template="/test#arguments.TargetPage#"/>
Unfortunately I got the same error.
So, is what I'm after even possible? (Windows Server 2008 and IIS in case it matters. ColdFusion 9.)
I know that I could put a CFINCLUDE in my index.cfm and pass around URLs like http://www.example.com/?file=test.cfm, but I'd prefer not to do that.
Well here's something: If I put an empty test.cfm in my web root then this works. Obviously I'd really rather not put empty stubs for every one of my files (which, for this project, will end up being in the hundreds).
Rather than spinning your wheels down this path, let me point you in a possible better direction which may solve the original issue, but from a more preferred/best practices standpoint:
ColdFusion Sourceless Deployment
Rather than trying to jimmy-rig the site to read files outside of root, you simply never put the source code out into the world.
I think you would have better luck using onMissingTemplate rather than onRequest. http://help.adobe.com/en_US/ColdFusion/9.0/CFMLRef/WSc3ff6d0ea77859461172e0811cbec22c24-7d2a.html
I'm looking for something like Response.Clear().
You can reset the output buffer using the cfcontent tag with the reset argument:
<cfcontent reset="true">
This will clear the response body and prevent the output of buffered content -
<cfset GetPageContext().getCFOutput().clear()>
The two existing answers (<cfset GetPageContext().getCFOutput().clear()> and <cfcontent reset="true">) will reset the main content buffer, but those commands will not reset the header buffers (i.e. content that ColdFusion automatically inserts into the <head> element such as <script> tags when using <cfchart>).
To reset everything, you can use either of the following approaches:
<cfcontent reset="true" resethead="true">
or
<cfset getPageContext().getCFOutput().clearAll()>
<cfset getPageContext().getCFOutput().clearHeaderBuffers()>
These approaches are not documented (so possible to change in future version -- though unlikely) and these approaches are unlikely to be portable to other CFML engines, but I have not found any documented approach for clearing the header buffers.
Related answer: Is there a way to prevent cfchart from forcing js into response content?