So, I've been using tntnet for a while, and loving every moment of it.  
It's a wonderful thing for web developers who want to harness the 
amazing power of C++ without having to complicate things when outputting 
straight HTML; a truly amazing synthesis of the two languages.  To show 
my thanks to the developer, and to the community, I'd like to give 
something back: I'm going to share with everyone a great way to include 
static content (such as images, stylesheets, javascript files, or 
anything else that doesn't require any dynamic output) without having to 
compile it into the program (which saves a lot of hassle by getting rid 
of the need to use the binary compile switch in ecppc.  This is 
especially useful if you're creating a site with user-uploadable 
images.  (And because this is so much simpler, I think it might be a 
nice idea to implement this into the base tntnet source somehow.)  I 
believe this would also be applicable to the recent thread on TinyMCE; I 
haven't read it completely, but I've seen a lot of discussion on 
compiling .js files... this method makes that unnecessary.

For this, you need two files, to add one ecpp file for each type of 
static content you want to serve (css, txt, html, jpg, png, etc).  The 
reason for having different files for each is twofold: firstly, you need 
to handle text-based content (html, javascript, css) differently from 
binary content (images, flash files, java applets); secondly, you need 
to manually set the MIME type for each file you send, because TNTnet 
will set it to text/html by default.  The great thing about this method, 
though, is that, unlike the default method, you don't have to recompile 
every time you make a tiny change to your CSS, which saves a lot of 
development time, and you don't have to recompile every time you make a 
slight change to an image file, or every time a new user uploads an 
avatar, etc.

Firstly, style.ecpp.  It's a fairly simple function, heavily commented 
for your benefit:

<%pre>
#include <fstream>
</%pre>
<{
    char c;
    std::ifstream f;

    /*
     * Find out the file they're searching for.
     * This will be a file relative to the current working directory (cwd).
     * Can include folder names.  Visiting www.yoursite.com/images/img.jpg
     * will therefore reference images/img.jpg in your cwd, which typically
     * will be the folder in which your executable is stored.
     */
    string fname = request.getQuery();

    // The filename will always have a preceding '/', so we want to 
remove that to search in the cwd.
    fname.erase(0, 1);

    //Now that we've found the name of the file we want, we try to open it.
    f.open (fname.c_str(), std::ios::in );
   
    if(!f)
    {
        // If f is NULL, then the file doesn't exist; call whatever 
"404" component you want, or just send a blank file.
        callComp("notfound", request, reply, qparam);
    }
    else
    {
        //Set the content type properly - DON'T FORGET THIS, especially 
for binary files!
        reply.setContentType("text/css");

        //Read the entire contents of the file, one char at a time, and 
send it back out to the client.
        while(f.good())
        {
            c = f.get();
            if(f.good())
                reply.out() << c;
        }
    }

    // Close the file.
    f.close();
}>

Now, that works great for text files, javascript files, css files, html 
files... anything containing plain text.  But if you try it with an 
image file, you'll notice you get strange results.  Only two lines of 
code have to be changed, however, for image files to work.

Firstly, you need to change the f.open line to "f.open (fname.c_str(), 
std::ios::in | std::ios::binary );".  Secondly, you need to make sure 
the content type is set properly (for png files, for example, it needs 
to be "image/png."  Other than that, the file can be copied identically.

You may ask, "Why not just put it all in a function like get_file( 
string fname, string contentType, bool is_binary, tnt::HttpRequest 
&request, tnt::HttpReply &reply, tnt::QueryParams &qparam)?"  The answer 
is that callComp is a protected member of the EcppComponent class, which 
means there's no way to call it outside of the .ecpp file, since 
everything within it is contained in a dynamically created class that 
extends the EcppComponent class.  You could make the function a boolean 
and then call the component in the .ecpp file only if it returns false, 
but when I tried to do that, the browser couldn't understand the output 
as an image for the binary files.  I'll continue looking into that and 
see if I can figure out what I did wrong, or if it's just a fundamental 
design flaw with that approach, and I'll send an update later.

Now, there's just one more thing that needs to be done: you need to map 
"^/(.*).png$" to "png.ecpp", and likewise for other extensions - 
"^/(.*).css$" to "style.ecpp", "^/(.*).jpg$" to "jpg.ecpp", etc.

I would also recommend using this as a stand-alone application (i.e., 
using a main.cpp and compiling an executable binary rather than relying 
on the installed tntnet runtime) if you want your static content to be 
in the same directory as the .ecpp files; otherwise, you'll probably 
need to place your images in the same directory as tntnet.  
Alternatively, you could place a "chdir( )" in all of your files to 
ensure you go to the directory you want.  (I haven't tested this, but 
I'm assuming the cwd for the main tntnet file would be the base tntnet 
directory.  It's possible it switches the cwd, though; I don't really 
feel like testing this, so someone else can give insight on this.)

And that's the scoop; with this, you should be able to easily handle 
arbitrary inclusion of static content in your site, making 
administration and modification of it a whole lot easier.  Enjoy it!

Shadowcat


------------------------------------------------------------------------------
Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day 
trial. Simplify your report design, integration and deployment - and focus on 
what you do best, core application coding. Discover what's new with
Crystal Reports now.  http://p.sf.net/sfu/bobj-july
_______________________________________________
Tntnet-general mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/tntnet-general

Reply via email to