Main Page   Data Structures   File List   Data Fields   Globals   Related Pages  

reqhandler_file.c

Go to the documentation of this file.
00001 /***************************************************************************
00002                               reqhandler_file.c
00003                              -------------------
00004     begin                : Sun Nov 25 2001
00005     copyright            : (C) 2001-2002 by Christian Hoenig & Gunter Ohrner
00006     email                : pdepp@CustomCDROM.de
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010  *                                                                         *
00011  *   This program is free software; you can redistribute it and/or modify  *
00012  *   it under the terms of the GNU General Public License as published by  *
00013  *   the Free Software Foundation; either version 2 of the License, or     *
00014  *   (at your option) any later version.                                   *
00015  *                                                                         *
00016  ***************************************************************************/
00017 
00023 #include "common.h"
00024 
00025 #include <errno.h>
00026 #include <fcntl.h>
00027 #include <limits.h>
00028 #include <stdlib.h>
00029 #include <string.h>
00030 #include <sys/types.h>
00031 #include <sys/stat.h>
00032 #include <unistd.h>
00033 
00034 #include "reqhandler_file.h"
00035 
00036 #include "buffer.h"
00037 #include "conftable.h"
00038 #include "http.h"
00039 #include "logger.h"
00040 #include "mime.h"
00041 #include "misc.h"
00042 #include "xmalloc.h"
00043 
00044 
00046 #define ALLOW "GET HEAD"
00047 
00048 
00049 // the struct containing all necessary information (on file-level) for a file transfer
00050 struct ReqHandlerFile
00051 {
00052   HttpProtHandler parent; 
00053   //no right neighbour
00054 
00055   char *abs_path;       
00056   int source;           
00057   int status;           
00058   size_t src_size;      
00059   time_t mod_time;      
00060   char *extension;      
00061   
00062   char *allow;          
00063 
00064   //the data buffer 
00065   struct Buffer buf;    
00066   int data_pending;     
00067   int error;            
00068 };
00069 
00070 
00071 //internal funktions
00072 int getAbsPath(char **abs_path, const char *path);
00073 int getSrcInfo(ReqHandlerFile this);
00074 
00075 
00076 
00077 // "global" variables with constant values
00078 static size_t send_buf_size;
00079 
00080 static const char * doc_root;
00081 static size_t doc_root_len;
00082 
00083 static const char * index_file;
00084 static size_t index_file_len;
00085 
00086 // pre-initialize constant values 
00087 int rhfModulePreInit()
00088 {
00089   // use user-defineable buffer size (if undefined use CONFENTRY_VAL_BUFSIZE)
00090   send_buf_size = getEntryDeflUI(CONFENTRY_KEY_SENDBUFFER, STD_CONFENTRY_VAL_SENDBUFFER);
00091 
00092   doc_root = getEntry(CONFENTRY_KEY_ROOTDIR);
00093   doc_root_len = strlen(doc_root);
00094 
00095   index_file = getEntryDefl(CONFENTRY_KEY_INDEXHTML, STD_CONFENTRY_VAL_INDEXHTML);
00096   index_file_len = strlen(index_file);
00097 
00098   return 0;
00099 }
00100 
00101 // clean up
00102 int rhfModuleTerminate()
00103 {
00104   return 0;
00105 }
00106 
00107 
00108 
00109 
00110 ReqHandlerFile rhfInit(HttpProtHandler parent, const char *path_buf, int change_path)
00111 {
00112   ReqHandlerFile this = (ReqHandlerFile) pd_malloc(sizeof(struct ReqHandlerFile));
00113   
00114   memset(this, 0, sizeof(struct ReqHandlerFile));
00115   this->parent = parent;
00116   this->source = -1;
00117   this->allow = ALLOW;
00118 
00119   // if change_path == true, the path is converted into an asolute path, otherwise not
00120   if (change_path)
00121   {
00122     if (getAbsPath(&this->abs_path, path_buf) == -1)
00123       this->error = errno;
00124   }
00125   else
00126   {
00127     char* new_buf = (char*) pd_malloc(strlen(path_buf)+1);
00128     strcpy(new_buf, path_buf);
00129     this->abs_path = new_buf;
00130   }
00131 
00132   if (getSrcInfo(this) == 0)
00133   {
00134     this->source = open(this->abs_path, O_RDONLY);
00135     if (this->source == -1)
00136     {
00137       logerr(REQUEST_HANDLER, ERROR, errno, "could not open requested file");
00138       this->error = errno;
00139     }
00140     else
00141     {
00142       // make buffer size of file if bufsize is larger, else take the default size
00143       if (this->src_size < send_buf_size)
00144       {
00145         /* Allocate data send buffer. If file size is zero, allocate
00146            at least one byte so EFence doesn't complain              */
00147         this->buf.data = (char*) pd_malloc(MAX(this->src_size, 1));
00148         this->buf.len  = this->src_size;
00149       }
00150       else
00151       {
00152         this->buf.data = (char*) pd_malloc(send_buf_size);
00153         this->buf.len  = send_buf_size;
00154       }
00155       this->buf.pos  = 0;
00156       this->data_pending = true;
00157     }
00158   }
00159   else if (this->error == 0)
00160     this->error = errno;
00161 
00162   return this;
00163 }
00164 
00166 int rhfReceive(__attribute__ ((unused)) ReqHandlerFile this,
00167                __attribute__ ((unused)) struct Buffer *buf /*recv_buf*/)
00168 {
00169   return 0;
00170 }
00171 
00172 int rhfSend(ReqHandlerFile this, struct Buffer **buf)
00173 {
00174   int cnt = 0; //amount of data read
00175   do {
00176     cnt = read(this->source, this->buf.data, this->buf.len);
00177   } while (cnt == -1 && errno == EINTR);
00178   
00179   this->buf.len = cnt;
00180   this->buf.pos = 0;
00181   if (cnt <= 0)
00182   {
00183     int errno_bak = errno;
00184     //nothing could be read anymore...
00185     pd_free(this->buf.data);
00186     this->buf.data = NULL;
00187     this->data_pending = false;
00188     //...but did an error occure or are we at the end of file?
00189     if (cnt != 0)
00190     {
00191       logerr(REQUEST_HANDLER, ERROR, errno_bak, "data could not be read");
00192       this->error = errno;
00193       return -1;
00194     }
00195   }
00196   else
00197     this->data_pending = true;
00198 
00199   *buf = &this->buf;
00200   
00201   //maybe
00202   //return this->buf.len;
00203   return 0;
00204 }
00205 
00207 int rhfProcess( __attribute__ ((unused))ReqHandlerFile this)
00208 {
00209   return 0;
00210 }
00211 
00212 int rhfIsDataPending(ReqHandlerFile this)
00213 {
00214   return (this->data_pending);
00215 }
00216 
00217 int rhfTerminate(ReqHandlerFile this)
00218 {
00219   if (this == NULL) return -1;
00220 
00221   pd_free(this->buf.data);
00222   this->buf.data = NULL;
00223   pd_free(this->abs_path);
00224 
00225   if (this->source > 0)
00226     close(this->source);
00227 
00228   // kill myself...
00229   pd_free(this);
00230   return 0;
00231 }
00232 
00233 int rhfGetError(ReqHandlerFile this)
00234 {
00235   return this->error;
00236 }
00237 
00238 
00239 //some non-standard public functions:
00240 
00241 size_t rhfGetSourceSize(ReqHandlerFile this)
00242 {
00243   return this->src_size;
00244 }
00245 
00246 time_t rhfGetModTime(ReqHandlerFile this)
00247 {
00248   return this->mod_time;
00249 }
00250 
00251 const char *rhfGetAllow(ReqHandlerFile this)
00252 {
00253   return this->allow;
00254 }
00255 
00256 
00257 const char* rhfGetContentType(ReqHandlerFile this)
00258 {
00259   //convert fileextension to mime-type and return
00260   return mimeLookup(this->extension);
00261 }
00262 
00266 //internal procedures:
00267 
00278 int getAbsPath(char** abs_path, const char* path)
00279 {
00280   char *dir;
00281   int ret_val = 0;
00282 
00283   if (doc_root == NULL || path == NULL)
00284   {
00285     errno = EBADF;
00286     return -1;
00287   }
00288   
00289   // concatenate rootpath and filepath
00290   dir = (char*) pd_malloc(doc_root_len + strlen(path)+1);
00291   strcpy(dir, doc_root);
00292   strcpy(dir + doc_root_len, path);
00293 
00294 
00296   *abs_path = (char*)pd_malloc(PATH_MAX+1);
00297   if (realpath(dir,*abs_path) != NULL)
00298   {
00299     struct stat buf;
00300     if (stat(*abs_path, &buf) == 0)
00301     {
00302       if (S_ISDIR(buf.st_mode))
00303       {// yes, we handle a directory and have to set a file
00304         char *tmp;
00305         struct stat tbuf;
00306         size_t abs_path_len = strlen(*abs_path);
00307 
00309         // strcat(*abs_path, "/");
00310         (*abs_path)[abs_path_len++] = '/';
00311         (*abs_path)[abs_path_len] = '\0';
00312           
00313         tmp = (char*)pd_malloc(abs_path_len + index_file_len + 1);
00314 
00315         strcpy(tmp, *abs_path);
00316         // strcat(tmp, index_file);
00317         strcpy(tmp + abs_path_len, index_file);
00318 
00319         errno = 0;
00320         
00321         if (stat(tmp, &tbuf) != 0)
00322         {// something went wrong ... free all and get outta here
00323           pd_free(dir);
00324           pd_free(tmp);
00325           pd_free(*abs_path); *abs_path = NULL;
00326           return -1;
00327         }
00328         pd_free(*abs_path);
00329         *abs_path = tmp;
00330       }
00331     }
00332     else
00333       //stat failed
00334       return -1;
00335 
00336     //check if we are still in valid dir-scope
00337     if (strncmp(*abs_path, doc_root, doc_root_len) == 0)
00338       ret_val = 0;
00339     else
00340     {
00341       pd_free(dir);
00342       pd_free(*abs_path); *abs_path = NULL;
00343       errno = EACCES;
00344       return -1;
00345     }
00346   }
00347   else
00348   {//realpath errored
00350     //save errno for later use:
00351     int errno_orig = errno;
00352     pd_free(dir);
00353     pd_free(*abs_path); *abs_path = NULL;
00354     errno = errno_orig;
00355     return -1;
00356   }
00357 
00358   pd_free(dir);
00359   return ret_val; 
00360 }
00361 
00362 
00372 int getSrcInfo(ReqHandlerFile this)
00373 {
00374   struct stat buf;
00375   int len;
00376   int cnt;
00377   
00378   //init ext to the whole path:
00379   this->extension = this->abs_path;
00380   
00381   if (this->abs_path == NULL) return -1;
00382   
00383   len = strlen(this->abs_path);
00384     
00385   if (stat(this->abs_path, &buf) == 0)
00386   {
00387     this->src_size = buf.st_size;
00388     this->mod_time = buf.st_mtime;
00389   }
00390   else
00391   {
00392     this->src_size = 0;
00393     this->mod_time = 0;
00394     return -1;
00395   }
00396   
00397   //set the pointer to the file extension
00398   //find fileextension devided by '.', if / ist last, the filename is taken
00399   for (cnt = 0; cnt < len; ++cnt)
00400     if (this->abs_path[cnt] == '.' || this->abs_path[cnt] == '/')
00401       this->extension = this->abs_path+cnt;
00402 
00403   //doesnt make sence, if the last char is a '.' or '/'
00404   if (this->extension > this->abs_path + len - 2)
00405     this->extension = this->abs_path;
00406   else
00407     //set the pointer to the char behind the '.' or '/'
00408     ++this->extension;
00409   
00410   return 0;
00411 }
00412 
00413 

Generated on Fri Jan 25 22:40:31 2002 for PDepp Webserver by doxygen1.2.11.1 written by Dimitri van Heesch, © 1997-2001