Can RewriteCond Check File Age ?

  • joebert
  • Fart Bubbles
  • Genius
  • User avatar
  • Posts: 13503
  • Loc: Florida

Post 3+ Months Ago

I have some mod_rewrite directives that check a cache directory for a static HTML file before rewriting the request for the PHP files to handle. This works great, but if I want to update my cache periodically I have to setup a cron-job / automated-task to delete the cached files from the cache so mod_rewrite doesn't hit on a -f RewriteCond , but instead skips the cache and regenerates the page.

What I'm wondering, is whether I can check both whether a file exists via the -f flag, and somehow check that the file is less than N hours old.
  • Anonymous
  • Bot
  • No Avatar
  • Posts: ?
  • Loc: Ozzuland
  • Status: Online

Post 3+ Months Ago

  • PolishHurricane
  • Mastermind
  • Mastermind
  • User avatar
  • Posts: 1585

Post 3+ Months Ago

I don't think it's possible man. I suggest either finding another method or perhaps modifying mod_rewrite? I know it sucks right... WTB new web server with better mods.
  • joebert
  • Fart Bubbles
  • Genius
  • User avatar
  • Posts: 13503
  • Loc: Florida

Post 3+ Months Ago

I took a at the source for mod_rewrite (modules/mappers/mod_rewrite.c) and it looks like it wouldn't be too tough to add a special RewriteCond flag for my purpose. It's probably more trouble than it's worth in the long run though.

I'd probably have to start by adding a new flag for my purpose.
Here's the enum. Adding a flag could force me to rewrite it if Apache adds a new flag later on, and I don't know how defining the constant outside of the enum for a number out of conflict range would work out.

C Code: [ Select ]
/* special pattern types for RewriteCond */
typedef enum {
    CONDPAT_REGEX = 0,
    CONDPAT_FILE_EXISTS, // -f flag
    CONDPAT_FILE_SIZE,
    CONDPAT_FILE_LINK,
    CONDPAT_FILE_DIR,
    CONDPAT_FILE_XBIT,
    CONDPAT_LU_URL,
    CONDPAT_LU_FILE,
    CONDPAT_STR_GT,
    CONDPAT_STR_LT,
    CONDPAT_STR_EQ
} pattern_type;
  1. /* special pattern types for RewriteCond */
  2. typedef enum {
  3.     CONDPAT_REGEX = 0,
  4.     CONDPAT_FILE_EXISTS, // -f flag
  5.     CONDPAT_FILE_SIZE,
  6.     CONDPAT_FILE_LINK,
  7.     CONDPAT_FILE_DIR,
  8.     CONDPAT_FILE_XBIT,
  9.     CONDPAT_LU_URL,
  10.     CONDPAT_LU_FILE,
  11.     CONDPAT_STR_GT,
  12.     CONDPAT_STR_LT,
  13.     CONDPAT_STR_EQ
  14. } pattern_type;


Then I'd have to jump down and work my flag into here.
I could keep it simple and just add a one character flag where it hardcoded in the 24 hours I'm looking for at the moment, but that wouldn't be very useful.
a2 is defined as "char *a2;" earlier up in the function, I'm not sure I could squeeze more bytes into that so I could append an interval to my flag or not.

C Code: [ Select ]
    /* determine the pattern type */
    newcond->ptype = CONDPAT_REGEX;
    if (*a2 && a2[1]) {
        if (!a2[2] && *a2 == '-') {
            switch (a2[1]) {
            case 'f': newcond->ptype = CONDPAT_FILE_EXISTS; break;
            case 's': newcond->ptype = CONDPAT_FILE_SIZE;   break;
            case 'l': newcond->ptype = CONDPAT_FILE_LINK;   break;
            case 'd': newcond->ptype = CONDPAT_FILE_DIR;    break;
            case 'x': newcond->ptype = CONDPAT_FILE_XBIT;   break;
            case 'U': newcond->ptype = CONDPAT_LU_URL;      break;
            case 'F': newcond->ptype = CONDPAT_LU_FILE;     break;
            }
        }
        else {
            switch (*a2) {
            case '>': newcond->ptype = CONDPAT_STR_GT; break;
            case '<': newcond->ptype = CONDPAT_STR_LT; break;
            case '=': newcond->ptype = CONDPAT_STR_EQ;
                /* "" represents an empty string */
                if (*++a2 == '"' && a2[1] == '"' && !a2[2]) {
                    a2 += 2;
                }
                break;
            }
        }
    }
  1.     /* determine the pattern type */
  2.     newcond->ptype = CONDPAT_REGEX;
  3.     if (*a2 && a2[1]) {
  4.         if (!a2[2] && *a2 == '-') {
  5.             switch (a2[1]) {
  6.             case 'f': newcond->ptype = CONDPAT_FILE_EXISTS; break;
  7.             case 's': newcond->ptype = CONDPAT_FILE_SIZE;   break;
  8.             case 'l': newcond->ptype = CONDPAT_FILE_LINK;   break;
  9.             case 'd': newcond->ptype = CONDPAT_FILE_DIR;    break;
  10.             case 'x': newcond->ptype = CONDPAT_FILE_XBIT;   break;
  11.             case 'U': newcond->ptype = CONDPAT_LU_URL;      break;
  12.             case 'F': newcond->ptype = CONDPAT_LU_FILE;     break;
  13.             }
  14.         }
  15.         else {
  16.             switch (*a2) {
  17.             case '>': newcond->ptype = CONDPAT_STR_GT; break;
  18.             case '<': newcond->ptype = CONDPAT_STR_LT; break;
  19.             case '=': newcond->ptype = CONDPAT_STR_EQ;
  20.                 /* "" represents an empty string */
  21.                 if (*++a2 == '"' && a2[1] == '"' && !a2[2]) {
  22.                     a2 += 2;
  23.                 }
  24.                 break;
  25.             }
  26.         }
  27.     }


Then I'd need to work out checking the age of the file here.
At first glance, I'd guess that something like "sb.mtime" would be available from apr_stat.
I'm not sure how I would access my interval, though perhaps I could work it out so that the RewriteCond parser set newcond->ptype to my interval once it determined it was using it.
Though, the interval would need to be seconds to reduce the chances of it conflicing with the other constants, yet, I bet seconds would be the way to go since any mtime returned is likely to be a UNIX timestamp. It would be awkward to have the interval be seconds, and force a restriction that it be greater than 60 seconds to prevent conflict though. Maybe have it be defined using minutes, then convert it to seconds in the module.

C Code: [ Select ]
static int apply_rewrite_cond(rewritecond_entry *p, rewrite_ctx *ctx)
{
    char *input = do_expand(p->input, ctx, NULL);
    apr_finfo_t sb;
    request_rec *rsub, *r = ctx->r;
    ap_regmatch_t regmatch[AP_MAX_REG_MATCH];
    int rc = 0;
 
    switch (p->ptype) {
    case CONDPAT_FILE_EXISTS:
        if (   apr_stat(&sb, input, APR_FINFO_MIN, r->pool) == APR_SUCCESS
            && sb.filetype == APR_REG) {
            rc = 1;
        }
        break;
 
    case CONDPAT_FILE_SIZE:
        if (   apr_stat(&sb, input, APR_FINFO_MIN, r->pool) == APR_SUCCESS
            && sb.filetype == APR_REG && sb.size > 0) {
            rc = 1;
        }
        break;
 
  1. static int apply_rewrite_cond(rewritecond_entry *p, rewrite_ctx *ctx)
  2. {
  3.     char *input = do_expand(p->input, ctx, NULL);
  4.     apr_finfo_t sb;
  5.     request_rec *rsub, *r = ctx->r;
  6.     ap_regmatch_t regmatch[AP_MAX_REG_MATCH];
  7.     int rc = 0;
  8.  
  9.     switch (p->ptype) {
  10.     case CONDPAT_FILE_EXISTS:
  11.         if (   apr_stat(&sb, input, APR_FINFO_MIN, r->pool) == APR_SUCCESS
  12.             && sb.filetype == APR_REG) {
  13.             rc = 1;
  14.         }
  15.         break;
  16.  
  17.     case CONDPAT_FILE_SIZE:
  18.         if (   apr_stat(&sb, input, APR_FINFO_MIN, r->pool) == APR_SUCCESS
  19.             && sb.filetype == APR_REG && sb.size > 0) {
  20.             rc = 1;
  21.         }
  22.         break;
  23.  
  • PolishHurricane
  • Mastermind
  • Mastermind
  • User avatar
  • Posts: 1585

Post 3+ Months Ago

You've seen this right?

http://apr.apache.org/docs/apr/0.9/stru ... 5602a41c60
http://apr.apache.org/docs/apr/0.9/grou ... 0c55aa02bb (microseconds)

Wouldn't something like this work?

C Code: [ Select ]
     case CONDPAT_FILE_M_EXISTS:
       int mhours = 2;
         if (   apr_stat(&sb, input, APR_FINFO_MIN, r->pool) == APR_SUCCESS
             && sb.filetype == APR_REG && sb.mtime > ((time(NULL) - (mhours * 3600)) * 1000000) ) {
             rc = 1;
         }
         break;
 
  1.      case CONDPAT_FILE_M_EXISTS:
  2.        int mhours = 2;
  3.          if (   apr_stat(&sb, input, APR_FINFO_MIN, r->pool) == APR_SUCCESS
  4.              && sb.filetype == APR_REG && sb.mtime > ((time(NULL) - (mhours * 3600)) * 1000000) ) {
  5.              rc = 1;
  6.          }
  7.          break;
  8.  


Which if I'm not mistaken would show the file exists as long as it wasn't modified more than 2 hours ago.
  • joebert
  • Fart Bubbles
  • Genius
  • User avatar
  • Posts: 13503
  • Loc: Florida

Post 3+ Months Ago

I have a feeling that somewhere in there, perhaps as a member of r->pool or input, there's going to be a timestamp for the request that could be accessed instead of working with the time routines and subsequent math.

Definitely looks like a start though. :D

Post Information

  • Total Posts in this topic: 5 posts
  • Users browsing this forum: No registered users and 77 guests
  • You cannot post new topics in this forum
  • You cannot reply to topics in this forum
  • You cannot edit your posts in this forum
  • You cannot delete your posts in this forum
  • You cannot post attachments in this forum
 
 

© 1998-2014. Ozzu® is a registered trademark of Unmelted, LLC.