00001
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "config.h"
00019 #include "defines.h"
00020
00021 #include <stdio.h>
00022 #include <stdlib.h>
00023 #include <string.h>
00024 #include <ctype.h>
00025 #include <time.h>
00026
00027 #include <sys/types.h>
00028 #include <sys/stat.h>
00029 #include <sys/time.h>
00030
00031 #include "hashlib.h"
00032 #include "readline.h"
00033 #include "utils.h"
00034 #include "configparser.h"
00035 #include "cfcgi.h"
00036 #include "template.h"
00037 #include "clientlib.h"
00038
00039
00040
00041 struct {
00042 int send_last_modified;
00043 long send_expires;
00044 int expires_set;
00045 int handle_last_modified_since;
00046 } http_config = { 0, 0, 0, 0 };
00047
00048 time_t flt_http_gmt_diff(void) {
00049 struct timeval now;
00050 time_t t1, t2;
00051 struct tm t;
00052
00053 gettimeofday(&now, NULL);
00054 t1 = now.tv_sec;
00055 t2 = 0;
00056
00057 t = *gmtime(&t1);
00058
00059 t.tm_isdst = 0;
00060 t2 = mktime(&t);
00061 return (time_t)difftime(t1, t2);
00062 }
00063
00064 int flt_http_get_month(const u_char *m) {
00065 if(cf_strncmp(m,"Jan",3) == 0) {
00066 return 0;
00067 }
00068 else if(cf_strncmp(m,"Feb",3) == 0) {
00069 return 1;
00070 }
00071 else if(cf_strncmp(m,"Mar",3) == 0) {
00072 return 2;
00073 }
00074 else if(cf_strncmp(m,"Apr",3) == 0) {
00075 return 3;
00076 }
00077 else if(cf_strncmp(m,"May",3) == 0) {
00078 return 4;
00079 }
00080 else if(cf_strncmp(m,"Jun",3) == 0) {
00081 return 5;
00082 }
00083 else if(cf_strncmp(m,"Jul",3) == 0) {
00084 return 6;
00085 }
00086 else if(cf_strncmp(m,"Aug",3) == 0) {
00087 return 7;
00088 }
00089 else if(cf_strncmp(m,"Sep",3) == 0) {
00090 return 8;
00091 }
00092 else if(cf_strncmp(m,"Oct",3) == 0) {
00093 return 9;
00094 }
00095 else if(cf_strncmp(m,"Nov",3) == 0) {
00096 return 10;
00097 }
00098 else if(cf_strncmp(m,"Dec",3) == 0) {
00099 return 11;
00100 }
00101
00102 return -1;
00103 }
00104
00105 long flt_http_get_lm(int sock) {
00106 #ifndef CF_SHARED_MEM
00107 rline_t tsd;
00108 u_char *line;
00109 long ret = 0;
00110
00111 if(writen(sock,"GET LASTMODIFIED 0\n",19) > 0) {
00112 memset(&tsd,0,sizeof(rline_t));
00113
00114 if((line = readline(sock,&tsd)) != NULL) {
00115 ret = strtol(line,NULL,0);
00116 free(line);
00117 }
00118 }
00119
00120 return ret;
00121 #else
00122 return *((time_t *)sock);
00123 #endif
00124 }
00125
00126 int flt_http_validate_cache(t_cf_hash *head,t_configuration *dc,t_configuration *vc,time_t lm,int sock) {
00127 t_module *mod;
00128 t_cache_revalidator fkt;
00129 size_t i;
00130 int ret = FLT_DECLINE;
00131
00132 if(Modules[0].elements) {
00133 for(i=0;i<Modules[0].elements && (ret == FLT_OK || ret == FLT_DECLINE);i++) {
00134 mod = array_element_at(&Modules[0],i);
00135
00136 if(mod->cfg->revalidator) {
00137 fkt = (t_cache_revalidator)mod->cfg->revalidator;
00138 ret = fkt(head,dc,vc,lm,sock);
00139 }
00140 }
00141 }
00142
00143 return ret;
00144 }
00145
00146 int flt_http_header_callbacks(t_cf_hash *head,t_cf_hash *header_table,t_configuration *dc,t_configuration *vc,int sock) {
00147 t_module *mod;
00148 t_header_hook fkt;
00149 size_t i;
00150 int ret = FLT_DECLINE;
00151 int retret = FLT_OK;
00152
00153 if(Modules[0].elements) {
00154 for(i=0;i<Modules[0].elements;i++) {
00155 mod = array_element_at(&Modules[0],i);
00156 if(mod->cfg->header_hook) {
00157 fkt = (t_header_hook)mod->cfg->header_hook;
00158 ret = fkt(head,header_table,dc,vc,sock);
00159
00160 if(ret == FLT_EXIT) retret = FLT_EXIT;
00161 }
00162 }
00163 }
00164
00165 return retret;
00166 }
00167
00168 time_t flt_http_lm_callbacks(t_cf_hash *head,t_configuration *dc,t_configuration *vc,int sock,time_t t1) {
00169 t_module *mod;
00170 t_last_modified fkt;
00171 size_t i;
00172 time_t ret;
00173
00174 if(Modules[0].elements) {
00175 for(i=0;i<Modules[0].elements;i++) {
00176 mod = array_element_at(&Modules[0],i);
00177 if(mod->cfg->header_hook) {
00178 fkt = (t_last_modified)mod->cfg->last_modified;
00179 ret = fkt(head,dc,vc,sock);
00180
00181 if(ret == (time_t)-1) continue;
00182 if(ret > t1) t1 = ret;
00183 }
00184 }
00185 }
00186
00187 return t1;
00188 }
00189
00190 int flt_http_execute(t_cf_hash *head,t_configuration *dc,t_configuration *vc,int sock) {
00191 u_char buff[100];
00192 time_t t,t1;
00193 struct tm *tm;
00194 struct tm tm_lm;
00195 u_char *lm;
00196 int ret;
00197 t_cf_hash *header_table = cf_hash_new(NULL);
00198 ub4 elems = hashsize(header_table->tablesize);
00199 ub4 i;
00200 t_cf_hash_entry *ent;
00201 time_t diff = flt_http_gmt_diff();
00202
00203
00204 ret = flt_http_header_callbacks(head,header_table,dc,vc,sock);
00205
00206 cf_hash_entry_delete(header_table,"Last-Modified",13);
00207
00208 for(i=0;i<elems;i++) {
00209 if(header_table->table[i]) {
00210 for(ent=header_table->table[i];ent;ent=ent->next) {
00211 printf("%s: %s\015\012",ent->key,(char *)ent->data);
00212 }
00213 }
00214 }
00215
00216 cf_hash_destroy(header_table);
00217
00218 if(ret == FLT_EXIT) return FLT_EXIT;
00219
00220
00221 if(http_config.handle_last_modified_since || http_config.send_last_modified) {
00222 t1 = flt_http_get_lm(sock);
00223 t1 = flt_http_lm_callbacks(head,dc,vc,sock,t1);
00224 tm = gmtime(&t1);
00225
00226 if(http_config.send_last_modified) {
00227 strftime(buff,100,"%a, %d %b %Y %H:%M:%S GMT",tm);
00228 printf("Last-Modified: %s\015\012",buff);
00229 }
00230
00231 if(http_config.handle_last_modified_since) {
00232 if((lm = getenv("HTTP_IF_MODIFIED_SINCE")) != NULL && *lm != '\0') {
00233 tm_lm.tm_mday = atoi(lm+5);
00234 tm_lm.tm_mon = flt_http_get_month(lm+8);
00235 tm_lm.tm_year = atoi(lm+12) - 1900;
00236 tm_lm.tm_wday = 0;
00237 tm_lm.tm_hour = atoi(lm+17);
00238 tm_lm.tm_min = atoi(lm+20);
00239 tm_lm.tm_sec = atoi(lm+23);
00240
00241 tm_lm.tm_yday = 0;
00242 tm_lm.tm_isdst = 0;
00243
00244 if((t = timegm(&tm_lm)) >= 0) {
00245 if(t >= t1) {
00246 ret = flt_http_validate_cache(head,dc,vc,t+diff,sock);
00247
00248 if(ret != FLT_EXIT) {
00249 printf("Status: 304 Not Modified\015\012\015\012");
00250 return FLT_EXIT;
00251 }
00252 }
00253 }
00254 }
00255 }
00256 }
00257
00258 return FLT_DECLINE;
00259 }
00260
00261 int flt_http_handle_command(t_configfile *cfile,t_conf_opt *opt,u_char **args,int argnum) {
00262 u_char *ptr = NULL;
00263
00264 if(argnum == 1) {
00265 if(cf_strcmp(opt->name,"SendLastModified") == 0) {
00266 http_config.send_last_modified = cf_strcasecmp(args[0],"yes") == 0;
00267 }
00268 else if(cf_strcmp(opt->name,"SendExpires") == 0) {
00269 http_config.expires_set = 1;
00270 http_config.send_expires = strtol(args[0],(char **)&ptr,10);
00271
00272 if(ptr) {
00273 if(toupper(*ptr) == 'M') {
00274 http_config.send_expires *= 60L;
00275 }
00276 else if(toupper(*ptr) == 'H') {
00277 http_config.send_expires *= 60L * 60L;
00278 }
00279 }
00280
00281 }
00282 else if(cf_strcmp(opt->name,"HandleLastModifiedSince") == 0) {
00283 if(cf_strcmp(args[0],"yes") == 0) {
00284 http_config.handle_last_modified_since = 1;
00285 }
00286 }
00287 }
00288 else {
00289 fprintf(stderr,"Expecting one argument for directive %s!\n",opt->name);
00290 return 1;
00291 }
00292
00293 return 0;
00294 }
00295
00296 int flt_http_set_headers(t_cf_hash *cgi,t_cf_hash *header_table,t_configuration *dc,t_configuration *vc,int sock) {
00297 char buff[BUFSIZ];
00298 size_t len;
00299 time_t t;
00300 struct tm *tm;
00301
00302 if(http_config.expires_set) {
00303 t = time(NULL) + http_config.send_expires;
00304 tm = gmtime(&t);
00305
00306 if(tm) {
00307 len = snprintf(buff,BUFSIZ,"public, max-age=%ld",http_config.send_expires);
00308 cf_hash_set(header_table,"Cache-Control",14,buff,len+1);
00309
00310 if((len = strftime(buff,BUFSIZ,"%a, %d %b %Y %H:%M:%S GMT",tm))) {
00311 cf_hash_set(header_table,"Expires",8,buff,len+1);
00312 }
00313 }
00314 }
00315
00316 return FLT_OK;
00317 }
00318
00319 int flt_http_validate(t_cf_hash *head,t_configuration *dc,t_configuration *vc,time_t last_modified,int sock) {
00320 u_char *uname = cf_hash_get(GlobalValues,"UserName",8);
00321 u_char *uconffile = NULL;
00322 struct stat st;
00323 int ret = FLT_DECLINE;
00324
00325 if(uname) {
00326 uconffile = get_uconf_name(uname);
00327
00328 if(uconffile) {
00329 if(stat(uconffile,&st) != -1) {
00330 if(st.st_mtime <= last_modified) ret = FLT_OK;
00331 }
00332
00333 free(uconffile);
00334 }
00335 }
00336
00337 return ret;
00338 }
00339
00340 time_t flt_http_lm(t_cf_hash *head,t_configuration *dc,t_configuration *vc,int sock) {
00341 u_char *uname = cf_hash_get(GlobalValues,"UserName",8);
00342 u_char *uconffile = NULL;
00343 struct stat st;
00344 time_t ret = -1;
00345
00346 if(uname) {
00347 uconffile = get_uconf_name(uname);
00348
00349 if(uconffile) {
00350 if(stat(uconffile,&st) != -1) {
00351 ret = st.st_mtime;
00352 }
00353
00354 free(uconffile);
00355 }
00356 }
00357
00358 return ret;
00359 }
00360
00361 t_conf_opt flt_http_config[] = {
00362 { "SendLastModified", flt_http_handle_command, NULL },
00363 { "SendExpires", flt_http_handle_command, NULL },
00364 { "HandleLastModifiedSince", flt_http_handle_command, NULL },
00365 { NULL, NULL, NULL }
00366 };
00367
00368 t_handler_config flt_http_handlers[] = {
00369 { CONNECT_INIT_HANDLER, flt_http_execute },
00370 { 0, NULL }
00371 };
00372
00373 t_module_config flt_http = {
00374 flt_http_config,
00375 flt_http_handlers,
00376 flt_http_validate,
00377 flt_http_lm,
00378 flt_http_set_headers,
00379 NULL
00380 };
00381
00382