3

Here's my script :

#include "gwan.h" // G-WAN exported functions
#include <string.h> // strstr()

int init(int argc, char *argv[])
{
    u32 *states = (u32*)get_env(argv, US_HANDLER_STATES);
    *states = 1 << HDL_AFTER_READ;
    return 0;
}

void clean(int argc, char *argv[])
{}

int main(int argc, char *argv[])
{
    if((long)argv[0] == HDL_AFTER_READ)
    {
        xbuf_t *read_xbuf = (xbuf_t*)get_env(argv, READ_XBUF);
        if(strstr(read_xbuf->ptr, "GET / HTTP/1.1"))
        {
            xbuf_repl(read_xbuf, "GET / HTTP/1.1", "GET /?index HTTP/1.1");
        }
        else
        {
            if(strstr(read_xbuf->ptr, ".c HTTP/1.1"))
            {
                int *pHTTP_status = (int*)get_env(argv, HTTP_CODE);
                if(pHTTP_status)
                    *pHTTP_status = 404;
                return 255;
            }
            xbuf_repl(read_xbuf, "GET /", "GET /?");
        }
    }
    return(255);
}

As you may understood, I'm trying to redirect the homepage to the dynamic file "hello.c". I'm also redirecting every request to the dynamic directory (without having to use the character "?") while preventing the use of the extension ".c" in the url.

This script works partly but obviously causes memory allocation issues. Would you have any solution to propose?

John S
  • 231
  • 3
  • 11
  • This script won't work on pipelined requests because you did not check that case. Plus, it ignores HTTP 1.0. See below for a simpler and more efficient solution. – Gil Mar 14 '13 at 07:14
  • I agree with you. My solution isn't the good one, but I don't know what to do to solve my problem... Mainly to redirect in the best way possible my homepage (mydomain.com/) to a dynamic file. – John S Mar 15 '13 at 14:31

2 Answers2

1

If you are worried about performance don't use strstr. It will search the whole request for a match.

Based on your script you are expecting all request to be GET so strncmp is better to use since you are only comparing the first 6 characters.

int main(int argc, char *argv[])
{
    xbuf_t *read_xbuf = (xbuf_t*)get_env(argv, READ_XBUF);
    if(strncmp(read_xbuf->ptr, "GET / ", 6) == 0)
    {
        xbuf_repl(read_xbuf, " / ", " /?index ");
    }
    else
    {
        int pos = 5; // Start checking after '/' in "GET /"
        while(pos < 20) // Only check first 15 characters
        {               // Adjust depend on longest servlet name
            if(read_xbuf->ptr[pos] == '.' && read_xbuf->ptr[pos+1] == 'c')  // If request contains '.' return 404
            {
                int *pHTTP_status = (int*)get_env(argv, HTTP_CODE);
                if(pHTTP_status)
                    *pHTTP_status = 404;
                return 255;
            }
        }
        xbuf_repl(read_xbuf, "GET /", "GET /?");
    }
    return(255);
}

Again checking for ".c". You only want to check the first N character.

If you are worried about memory allocation caused by adding '?' to every request you need to design your servlet name so in-place replace can happen. Here is a link that have samples on how to achieve in-place replace for better performance.

RESTful URIs in G-WAN

I haven't tested the code above so it might not work but at least you will get an idea on how to do it. Also the script doesn't handle pipe-lined request.

Richard Heath
  • 349
  • 3
  • 12
  • your script is actually faster and cleaner but as you say, the main concern is still present (pipe-line doesn't handle) ! Anyway you website is very interesting ;) – John S Mar 17 '13 at 03:28
0

First, trying to avoid the *.c script extension is useless: by default, G-WAN accepts requests like /?hello which are automatically remapped into /?hello.c.

Second, this is not specific to C as G-WAN lets you define wich programming language (among the 16 scripted languages supported) will be used as the "default" language.

Third, you can also define another character if you want to avoid the '?' in your requests. G-WAN lets you chose among the non-reserved characters, making it possible to use use /'hello or /_hello instead of /?hello.cpp (see below all your options).

And, all this can be done without calling a handler for each request (so it will not churn memory):

int init(int argc, char *argv[])
{
   // the QUERY_CHAR character can be chosen from the following set: 
   //  - _ . ! ~ * ' ( ) 
   // (see RFC 2396, section "2.3. Unreserved Characters")
   //   
   u8 *query_char = (u8*)get_env(argv, QUERY_CHAR);
   *query_char = '!'; // use "/!hello.c" instead of "/?hello.c"

   // by default, DEFAULT_LANG = LG_C (ANSI C)
   // LG_C, LG_CPP, LG_JAVA, etc. are defined in /gwan/include/gwan.h
   // and in http://gwan.com/api#env
   //
   u8 *lang = (u8*)get_env(argv, DEFAULT_LANG);
   *lang = LG_CPP; // use "/!hello" instead of "/!hello.cpp"
   return 0;
}

// if, like above, init() does not define notification states with
// get_env(argv, US_HANDLER_STATES), then the main() and clean() 
// handler calls defined below will never be invoked
// (URL rewriting can't be done faster)
//
void clean(int argc, char *argv[]) { }
int  main (int argc, char *argv[]) { return 255; }

So, to come back to your question, you could use /'hello without doing any rewrite.

Gil
  • 3,279
  • 1
  • 15
  • 25
  • I check the presence of the '.c' character to prevent my visitors from knowing the programmation language I'm using ("mondomaine.com/?hello.c" will so redirect to a 404 page). Concerning the '?' character, I just wish to make it disappear from my visitors' point of view. A perfect address for me would be : "mondomaine.com/hello" instead of "mondomaine.com/?hello.c". – John S Mar 15 '13 at 13:44
  • Then, reserve a "junk" character and do an "inplace" rewrite. That's faster and safer than noving memory blocks. – Gil May 14 '13 at 13:50