Main Page   Data Structures   File List   Data Fields   Globals   Related Pages  

http.c

Go to the documentation of this file.
00001 /***************************************************************************
00002                                   http.c
00003                              -------------------
00004     begin                : Fri Nov 23 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 
00022 #include "common.h"
00023 
00024 #include <ctype.h>
00025 #include <errno.h>
00026 // logger.h includes stdio.h for us. Even more importantly it includes stdarg.h
00027 // BEFORE including stdio.h which avoids tons of warnings on Solaris... :-(
00028 #include <stdlib.h>
00029 #include <string.h>
00030 #ifdef TM_IN_SYS_TIME
00031 # include <sys/time.h>
00032 #else
00033 # include <time.h>
00034 #endif
00035 #include <unistd.h>
00036 
00037 #include "logger.h"
00038 #include "http.h"
00039 
00040 #include "buffer.h"
00041 #include "bufplist.h"
00042 #include "conftable.h"
00043 #include "conn_handler.h"
00044 #include "misc.h"
00045 #include "reqhandler_file.h"
00046 #include "xmalloc.h"
00047 
00048 
00050 int reply_server_name;
00051 
00052 
00054 enum Method     {MUNKNOWN, GET, HEAD, POST};
00056 enum HttpVer    {VUNKNOWN, V09, V10, V11};
00058 enum Encoding   {EUNKNOWN, IDENTITY, GZIP, COMPRESS};
00060 enum Connection {CUNKNOWN, CLOSE, KEEPALIVE};
00061 
00062 
00064 struct Uri
00065 {
00066   char* server; 
00067   int port;     
00068   char* path;   
00069   int valid;    
00070 };
00071 
00073 struct HttpRequestHdr
00074 {
00075   enum Method     mthd;             
00076   enum HttpVer    ver;              
00077   struct Uri      uri;              
00078 
00079   enum Encoding   content_encoding; 
00080   time_t          if_mod_since;     
00081   char*           from;            
00082   char*           usr_agent;       
00083   struct Uri      referer;          
00084   enum Connection connection;       
00085   //NOT IMPLEMENTED
00086   //char*         authorisation;   ///< credentials
00087 };
00088 
00089 
00090 
00095 struct HttpProtHandler
00096 {
00097   ConnHandler       parent;         
00098   ReqHandlerFile    rh_file;        
00099   int               status;         
00100   int               entity_available; 
00101                                     // we cannot use status to determine this as
00102                                     // we will have an error message to send
00103                                     // in case of an error if we can find one.
00104   BufpList          hdr_list;       
00105 
00106   // line buffer state
00107   struct Buffer line_buf;           
00108   ssize_t last_cr_pos;              
00109   int newline;                      
00110 
00111   struct HttpRequestHdr req_hdr;    
00112   int header_read;                  
00113   int method_read;                  
00114 
00115   int header_sent;                  
00116 
00117   int data_pending;                 
00118   int error;                        
00119 };
00120 
00124 
00125 // some internal functions:
00126 int          htRecvLine(HttpProtHandler this, const char* str);
00127 int          copyRequestLine(HttpProtHandler this, struct Buffer* buf);
00128 int          htMthdParse(HttpProtHandler this, const char* str);
00129 int          htAddData(struct HttpRequestHdr* hdr, const char* str);
00130 struct Uri   resolvURI(const char* str);
00131 const char*  getStatusAsText(HttpProtHandler this);
00132 int          buildBasicHeader(HttpProtHandler this);
00133 int          buildEntityHeader(HttpProtHandler this);
00134 int          appendHdrField(BufpList hdr_list, char* prefix, char* data);
00135 int          err2Status(int err);
00136 
00140 
00141 // pre-initialize constant values 
00142 int htModulePreInit()
00143 {
00144   if (strcmp(getEntryDefl(CONFENTRY_KEY_REPLYSERVERNAME,
00145                           STD_CONFENTRY_VAL_REPLYSERVERNAME),
00146                           CONFENTRY_VAL_TRUE) == 0)
00147   {
00148     reply_server_name = true;
00149   }
00150 
00151   return 0;
00152 }
00153 
00154 // clean up
00155 int htModuleTerminate()
00156 {
00157   return 0;
00158 }
00159 
00163 
00164 // initialize protocol handler
00165 HttpProtHandler htInit(ConnHandler parent)
00166 {
00167   HttpProtHandler this = (HttpProtHandler) pd_malloc(sizeof(struct HttpProtHandler));
00168   memset(this, 0, sizeof(struct HttpProtHandler));
00169   this->parent = parent;
00170   //set status initially to OK
00171   this->status = 200;
00172   this->entity_available = false;
00173   this->hdr_list = bufpListInit();
00174   
00175   this->line_buf = bufInit((char*) pd_malloc(256), 256, 0);
00176 
00177   return this;
00178 }
00179 
00180 
00181 // receive a block of data
00182 int htReceive(HttpProtHandler this, struct Buffer buf)
00183 {
00184   if (this->header_read == false) // parse http header
00185   {
00186     while (copyRequestLine(this, &buf) == 0        // read complete line?
00187            && this->error == E_SUCCESS             // no error occured?
00188            && this->header_read == false)          // still in header?
00189     {
00190       // there is some header data
00191       htRecvLine(this, this->line_buf.data);
00192       this->line_buf.pos = 0;
00193     }
00194     // if still in header, reset receive buffer
00195     if (this->header_read == false)
00196       this->last_cr_pos -= buf.len;
00197     else
00198     {
00200     }
00201   }
00202 
00203   return (this->error == E_SUCCESS) ? 0 : -1;
00204 }
00205 
00206 
00207 // process a request to send some data
00208 int htSend(HttpProtHandler this, struct Buffer** buf)
00209 {
00210   if (this->header_sent != true)
00211   { // send our data first
00212 
00213     *buf = bufpListGetPayload(this->hdr_list);
00214     bufpListNext(this->hdr_list);
00215 
00216     // is the header completely send?
00217     if (bufpListIsTail(this->hdr_list) == true)
00218     {
00219       this->header_sent = true;
00220       // If we have no entity to send we must keep our data_pending true
00221       // to reenter this function and signal that we're finished.
00222       this->data_pending = (this->entity_available) ? false : true;
00223     }
00224   }
00225   else
00226   {   // send our children's data
00227     if (this->req_hdr.mthd == HEAD)
00228     {
00229       pd_free((*buf)->data);
00230       (*buf)->data = NULL;
00231     }
00232     else if (rhfIsDataPending(this->rh_file) == true)
00233       rhfSend(this->rh_file, buf);
00234   }
00235   return 0;
00236 }
00237 
00238 
00239 // process some data, that's a NOOP in this request handler
00240 int htProcess(HttpProtHandler this)
00241 {
00242   // i have nothing to do, but give my child the chance to do smth
00243   if (this->rh_file == NULL)
00244     return 0;
00245   else
00246     return rhfProcess(this->rh_file);
00247 }
00248 
00249 
00250 // tell the connection handler if there is any data waiting to be sent,
00251 int htIsDataPending(HttpProtHandler this)
00252 {
00253   return (this->data_pending
00254           || ((this->rh_file != NULL) ? rhfIsDataPending(this->rh_file) : 0));
00255 }
00256 
00257 
00258 // destroy object and free all allocated ressources
00259 int htTerminate(HttpProtHandler this)
00260 {
00261   if (this == NULL) return -1;
00262   //terminate the underlying handler
00263   rhfTerminate(this->rh_file);
00264 
00265   //free items of hdr_list
00266   bufpListFirst(this->hdr_list);
00267   while(!bufpListIsTail(this->hdr_list))
00268   {
00269     struct Buffer* buf = bufpListGetPayload(this->hdr_list);
00270     pd_free(buf->data);
00271     pd_free(buf);
00272     bufpListDelete(this->hdr_list);
00273   }
00274   bufpListTerminate(this->hdr_list);
00275 
00276   //free all allocated memory
00277   pd_free(this->line_buf.data);
00278   pd_free(this->req_hdr.uri.server);
00279   pd_free(this->req_hdr.uri.path);
00280   pd_free(this->req_hdr.from);
00281   pd_free(this->req_hdr.usr_agent);
00282   pd_free(this->req_hdr.referer.server);
00283   pd_free(this->req_hdr.referer.path);
00284 
00285   //kill myself ... good bye
00286   pd_free(this);
00287 
00288   return 0;
00289 }
00290 
00291 // return the last error noticed
00292 int htGetError(HttpProtHandler this)
00293 {
00294   return this->error;
00295 }
00296 
00300 
00301 //internal procedures:
00302 
00304 int htRecvLine(HttpProtHandler this, const char* line)
00305 {
00306   // If we cannot find a customized-error-message file we fall back to a hardcoded
00307   // which we will store here.
00308   char* err_msg_data = NULL;
00309 
00310   //do we have to process the header?
00311   if (this->header_read == false)
00312   {
00313     //check if empty line is found (= end of header)
00314     if (*line == '\0')
00315       this->header_read = true;
00316     else
00317     {
00318       //is the method line read? else we can add additional lines of the request
00319       if (this->method_read == false)
00320       {
00321         memset(&this->req_hdr, 0, sizeof(struct HttpRequestHdr));
00322         if (htMthdParse(this, line) >= 0)
00323         {
00324           //no error occured and we are done
00325           this->method_read = true;
00326           // is this a HTTP/0.9 call?
00327           if (this->req_hdr.ver == V09)
00328             this->header_read = true;
00329         }
00330       }
00331       else
00332         //read more information:
00333         htAddData(&this->req_hdr, line);
00334     }
00335   }
00336 
00337   //the header is read completely, so we can start handling the file
00338   if (this->header_read == true)
00339   {
00340     // rh_file not existing?
00341     if(this->rh_file == NULL)
00342     {
00343       //we can only process GET and HEAD (if prot ver > 0.9 !) here
00344       if (this->req_hdr.mthd == GET
00345           || (this->req_hdr.mthd == HEAD && this->req_hdr.ver != V09))
00346       {
00347         int err;
00348         // we init the file and check if an error occured...
00349         this->rh_file = rhfInit(this, this->req_hdr.uri.path, true);
00350 
00351         if ((err = rhfGetError(this->rh_file)) == E_SUCCESS)
00352         {
00353           // everything went ok
00354           this->entity_available = true;
00355         } else
00356           // Error! We find out, what happened.
00357           this->status = err2Status(err);
00358 
00359         //check for If-Modified-Since
00360         if (this->status == 200 && this->req_hdr.if_mod_since != 0)
00361         {
00362           if (difftime(this->req_hdr.if_mod_since, rhfGetModTime(this->rh_file)) >= 0)
00363             //Not Modified
00364             this->status = 304;
00365         }
00366         
00367       }
00368       else
00369       { //the method could not be handled yet (mthd != GET, HEAD)
00370         if (this->req_hdr.mthd == MUNKNOWN
00371             || (this->req_hdr.mthd == HEAD && this->req_hdr.ver == V09))
00372             //a bad request!
00373           this->status = 400;
00374         else
00375           //unknown
00376           this->status = 501;
00377       }
00378 
00379       // we can not handle the file if not all OK, so we answer with an error!
00380       if (this->status != 200)
00381       {
00382         char errfile[9]; // "404.html"
00383         
00384         // rh_file is terminated, and we can init a new one containing the error
00385         if (this->rh_file != NULL)
00386           rhfTerminate(this->rh_file);
00387         snprintf(errfile, 9, "%d.html", this->status);
00388         this->rh_file = rhfInit(this, errfile, false);
00389         
00390         if (rhfGetError(this->rh_file) != E_SUCCESS)
00391         {
00392           char errmsg[] = "<html>"
00393                           "<head><title>Error %d while processing request</title></head>"
00394                           "<body>Error %d occured while processing your request.</body>"
00395                           "</html>";
00396           err_msg_data = (char*) pd_malloc(strlen(errmsg)+3);
00397           sprintf(err_msg_data, errmsg, this->status, this->status);
00398           // There is no body that could be used to create an entity header. :-(
00399           this->entity_available = false;
00400         }
00401         else
00402         {
00403           // we change the method to GET, so that the error file is shown
00404           if (this->req_hdr.ver == V09)
00405             this->req_hdr.mthd = GET;
00406           this->entity_available = true;
00407         }
00408       }
00409     }
00410 
00411     // there is no header in V09 ;-)
00412     if (this->req_hdr.ver == V09 )
00413     {
00414       if (err_msg_data == NULL)
00415         this->header_sent = true;
00416     }
00417     else
00418     {
00419       //builds the basic header used in all answers
00420       buildBasicHeader(this);
00421 
00422       if (this->entity_available /* this->status == 200 */
00423           && (this->req_hdr.mthd == GET || this->req_hdr.mthd == HEAD))
00424       {
00425         buildEntityHeader(this);
00426       }
00427 
00428       if (err_msg_data == NULL)
00429       {
00430         // terminate header by adding "\r\n"
00431         appendHdrField(this->hdr_list, NULL, NULL);
00432       } else {
00433         // add our hard coded error message
00434         appendHdrField(this->hdr_list, "Content-Type", "text/html");
00435         appendHdrField(this->hdr_list, NULL, NULL);
00436 //        if (this->req_hdr.mthd == GET)
00437 //          appendHdrField(this->hdr_list, NULL, err_msg_data);
00438 //        // Ok, there is no file that could be read...
00439 //        this->req_hdr.mthd = HEAD;
00440 //        pd_free(err_msg_data);
00441       }
00442 //      // reset header line list
00443 //      bufpListFirst(this->hdr_list);
00444     }
00445 
00446     // Do we have to send the hard coded error message?
00447     if (err_msg_data != NULL)
00448     {
00449       if (this->req_hdr.mthd == GET || this->req_hdr.ver == V09)
00450         appendHdrField(this->hdr_list, NULL, err_msg_data);
00451       // Ok, there is no file that could be read...
00452       this->req_hdr.mthd = HEAD;
00453       pd_free(err_msg_data);
00454     }
00455 
00456     // reset header line list
00457     bufpListFirst(this->hdr_list);
00458 
00459     //we have somthing for parent (the header!)
00460     this->data_pending = true;
00461   }
00462   return 0;
00463 }
00464 
00465 
00474 int copyRequestLine(HttpProtHandler this, struct Buffer* buf /*size_t recv_data_len*/)
00475 {
00476   int real_newline = 0;
00477   size_t last_lf_pos;
00478 
00479   for (; buf->pos < buf->len; ++buf->pos)
00480   {
00481     char cur_chr = *(buf->data + buf->pos);
00482     // rest of the previous line?
00483     if (this->newline && cur_chr != ' ') break;
00484     switch(cur_chr)
00485     {
00486     case '\n':
00487       last_lf_pos = buf->pos;
00488       if (this->last_cr_pos == (ssize_t) buf->pos-1) this->newline = 1;
00489       break;
00490     case '\r':
00491       this->last_cr_pos = buf->pos;
00492       break;
00493     default:
00494       *(this->line_buf.data + this->line_buf.pos++) = cur_chr;
00495       // line buffer full?
00496       if (this->line_buf.pos == this->line_buf.len)
00497       {
00498         char* new_buf = pd_realloc(this->line_buf.data, this->line_buf.len+=1024);
00499         if (new_buf == NULL)
00500         {
00501           logerr(PROT_HANDLER, CRITICAL, ENOMEM, "out of memory");
00503           exit(EXIT_FAILURE);
00504         }
00505         this->line_buf.data = new_buf;
00506       }
00507     }
00508   }
00509 //  If the end of recv_buf is NOT yet reached but this->newline is set,
00510 //   we found the end of a logical line. An empty line is ALWAYS a
00511 //   complete logical line itself.
00512   
00513   if (buf->pos != buf->len                // newline with trailing non-space
00514       || (this->line_buf.pos == 0  && this->newline == true) // empty line
00515       || (this->method_read == false && this->newline == true)) // first line read (method)
00516   {
00517     this->newline = false;
00518     real_newline = true;
00519   }
00520   else
00521     real_newline = false;
00522 
00523   // terminate line buffer after the end of a logical line
00524   if (real_newline) *(this->line_buf.data + this->line_buf.pos) = '\0';
00525 
00526   return real_newline ? 0 : -1;
00527 }
00528 
00529 
00531 #define MKHTTPRESPONSE_TIME_BUF_LEN 30
00532 
00534 // 0 on success, -1 on failure
00535 char* timetToStr(time_t t, struct Buffer* time_buf)
00536 {
00537   size_t time_str_len;
00538 
00539   time_str_len = strftime(time_buf->data, time_buf->len,
00540                            "%a, %d %b %Y %H:%M:%S GMT", gmtime(&t));
00541   
00542   return (time_str_len == 0) ? "" : time_buf->data;
00543 }
00544 
00546 time_t strToTimet(const char* str)
00547 {
00548   time_t time;
00549   struct tm t;
00550   int offset = 0;
00551 
00552   //init t
00553   memset(&t, 0, sizeof(struct tm));
00554 
00555   //"remove" leading spaces
00556   while (isspace((int) *(str+offset)))  offset++;
00557 
00558   //convert rfc1123 conform timestring
00559   if (strptime(str+offset, "%a, %d %b %Y %T GMT", &t) != NULL) ;
00560   //convert rfc850 conform timestring
00561   else if(strptime(str+offset, "%a, %d-%m-%Y %T GMT", &t) != NULL);
00562   //convert asctime conform timestring
00563   else if(strptime(str+offset, "%a %b %d %T %Y", &t) != NULL);
00564     else
00565     {
00566       logger(PROT_HANDLER, WARNING, "A time-string could not be handled (strptime)");
00567       return -1;
00568   }
00569   //convert tm to time_t
00570   if ((time = mktime(&t)) < 0)
00571   {
00572     logger(PROT_HANDLER, WARNING, "A time-string could not be handled (mktime)");
00573     return -1;
00574   }
00575   //since mktime converts t to localtime, i have to reconvert it to GMT
00576   //using the global variable timezone (not available on BSD, so we use the field tm_gmtoff)!
00577 #ifdef HAVE_STRUCT_TM_GMTOFF
00578   // this one is a BSD extension but we like it :-)
00579   time += t.tm_gmtoff;
00580 #else
00581   // this one is documented in the GNU man pages
00582   time -= timezone;
00583   // a detail which is NOT documented: timzone counts position west of GMT to have
00584   // positive offsets, exactly the opposite of what the BSD function does...
00585 #endif
00586   
00587   return time;
00588 }
00589 
00598 int buildBasicHeader(HttpProtHandler this)
00599 {
00600   struct Buffer* hdr_field;
00601   char time_buf[MKHTTPRESPONSE_TIME_BUF_LEN];
00602   const char* tmp_chr;
00603   struct Buffer* tmp_buf;
00604   time_t tmp_time = time(NULL);
00605   size_t len;
00606 
00607   // status line: HTTP/1.0 %d %s\r\n
00608   // HTTP/1.0 + Whitespaces + return code + text
00609   tmp_chr = getStatusAsText(this);
00610   len = 4 + 1 + 3 + 2 + 3 + strlen(tmp_chr) + 2 + 1;
00611   hdr_field = bufpInit((char*) pd_malloc(len), len-1, 0);
00612   snprintf(hdr_field->data, len, "HTTP/1.0 %d %s\r\n", this->status, tmp_chr);
00613   bufpListAppend(this->hdr_list, hdr_field);
00614 
00615   // Date: %s
00616   //         vv includes trailing 0 vv
00617   len = 6 + MKHTTPRESPONSE_TIME_BUF_LEN + 2;
00618   hdr_field = bufpInit((char*) pd_malloc(len), len-1, 0);
00619   tmp_buf = bufpInit(time_buf, MKHTTPRESPONSE_TIME_BUF_LEN, 0);
00620   snprintf(hdr_field->data, len, "Date: %s\r\n", timetToStr(tmp_time, tmp_buf));
00621   pd_free(tmp_buf);
00622   bufpListAppend(this->hdr_list, hdr_field);
00623 
00624   // Server: %s
00625   if (reply_server_name)
00626   {
00627     len = 6 + 2 + strlen(SERVERNAME_NSP) + 1 + strlen(SERVERVERSION_NSP) + 2 + 1;
00628     hdr_field = bufpInit((char*) pd_malloc(len), len-1, 0);
00629     snprintf(hdr_field->data, len, "Server: %s/%s\r\n", SERVERNAME_NSP, SERVERVERSION_NSP);
00630     bufpListAppend(this->hdr_list, hdr_field);
00631   }
00632 
00633   // Connection: close
00634   len = 17 + 2 + 1; //= strlen("Connection: close") + 2 + 1;
00635   hdr_field = bufpInit((char*) pd_malloc(len), len-1, 0);
00636   snprintf(hdr_field->data, len, "%s", "Connection: close\r\n");
00637   bufpListAppend(this->hdr_list, hdr_field);
00638 
00639   return 0;
00640 }
00641 
00649 int buildEntityHeader(HttpProtHandler this)
00650 {
00651   //Allow: (...)
00652   struct Buffer buf;
00653   buf.data = (char*)rhfGetAllow(this->rh_file);
00654   appendHdrField(this->hdr_list, "Allow", buf.data);
00655 
00656   //Content-Type: (...)
00657   buf.data = (char*)rhfGetContentType(this->rh_file);
00658   if (buf.data != NULL)
00659     appendHdrField(this->hdr_list, "Content-Type", buf.data);
00660 
00661   //Content-Length: xx
00662   buf.data = (char*) pd_malloc(100);
00663   snprintf(buf.data, 100, "%u", rhfGetSourceSize(this->rh_file));
00664   appendHdrField(this->hdr_list, "Content-Length", buf.data);
00665   pd_free(buf.data);
00666 
00667   //Last-Modified: (...)
00668   buf.len = MKHTTPRESPONSE_TIME_BUF_LEN;
00669   buf.data = (char*) pd_malloc(buf.len);
00670   timetToStr(rhfGetModTime(this->rh_file), &buf);
00671   appendHdrField(this->hdr_list, "Last-Modified", buf.data);
00672   pd_free(buf.data);
00673 
00674   return 0;
00675 }
00676 
00679 int appendHdrField(BufpList hdr_list, char* prefix, char* data)
00680 {
00681   struct Buffer* buf = (struct Buffer*) pd_malloc(sizeof(struct Buffer));
00682   size_t prefix_len;
00683 
00684   buf->pos = 0;
00685   if (prefix == NULL && data == NULL)
00686   {
00687     buf->len = 2;
00688     buf->data = (char*) pd_malloc(buf->len+1);
00689   }
00690   else if (data == NULL)
00691     return -1;
00692   else
00693   {
00694     if (prefix == NULL)
00695     {
00696       prefix_len = 0;
00697       buf->len = strlen(data) + 2;
00698       buf->data = (char*) pd_malloc(buf->len+1);
00699     } else {
00700       prefix_len = strlen(prefix);
00701       //                    ":<sp>"            "\r\n"
00702       buf->len = prefix_len + 2 + strlen(data) + 2;
00703       buf->data = (char*) pd_malloc(buf->len+1);
00704       strcpy(buf->data, prefix);
00705       //divide prefix and data by ": "
00706       buf->data[prefix_len++] = ':';
00707       buf->data[prefix_len++] = ' ';
00708     }
00709     strcpy(buf->data + prefix_len, data);
00710   }
00711   //delimit the line
00712   buf->data[buf->len - 2] = '\r';
00713   buf->data[buf->len - 1] = '\n';
00714   buf->data[buf->len - 0] = '\0';
00715 
00716   //append HdrFiled to the hdr_list
00717   bufpListAppend(hdr_list, buf);
00718 
00719   return 0;
00720 }
00721 
00723 int htMthdParse(HttpProtHandler this, const char* str)
00724 {
00725   int beg = 0;
00726   int end = 0;
00727   int crlf = 0;
00728 
00729   //Parsing of header...
00730   //...first the method...
00731   if ((crlf = getNextValue(&beg, &end, end, str)) != 0)
00732     this->status = 400;
00733   else
00734   {
00735     //the only methods wo know as HTTP/1.0 - server
00736     if ((strncmp(str+beg, "GET", end-beg+1) == 0) && ((end-beg+1) == (int)strlen("GET")))
00737       this->req_hdr.mthd = GET;
00738     else if ((strncmp(str+beg, "HEAD", end-beg+1) == 0) && ((end-beg+1) == (int)strlen("HEAD")))
00739       this->req_hdr.mthd = HEAD;
00740     else if ((strncmp(str+beg, "POST", end-beg+1) == 0) && ((end-beg+1) == (int)strlen("POST")))
00741       this->req_hdr.mthd = POST;
00742     else
00743     {
00744       this->req_hdr.mthd = MUNKNOWN;
00745       //bad request
00746       this->status = 400;
00747     }
00748   }
00749 
00750   //...then URI...
00751   if((crlf = getNextValue(&beg, &end, end+1, str)) != 0)
00752     this->status = 400;
00753   else
00754   {
00755     char* tmp = pd_malloc(end-beg+2);
00756 
00757     strncpy(tmp, str+beg, end-beg+1);
00758     *(tmp+end-beg+1) = '\0';
00759     this->req_hdr.uri = resolvURI(tmp);
00760 
00761     pd_free(tmp);
00762   }
00763 
00764   //...and at last HTTP Version
00765   if((crlf = getNextValue(&beg, &end, end+1, str)) != 0)
00766       this->req_hdr.ver = V09;
00767   else
00768   {
00769     if (strncmp(str+beg,"HTTP/0.9",end-beg+1) == 0  && ((end-beg+1) == 8))
00770       this->req_hdr.ver = V09;
00771     else if (strncmp(str+beg,"HTTP/1.0",end-beg+1) == 0  && ((end-beg+1) == 8))
00772       this->req_hdr.ver = V10;
00773     else if (strncmp(str+beg,"HTTP/1.1",end-beg+1) == 0  && ((end-beg+1) == 8))
00774       this->req_hdr.ver = V11;
00775     else
00776       this->req_hdr.ver = VUNKNOWN;
00777   }
00778   return (this->status == 200) ? 0 : -1;
00779 }
00780 
00782 int htAddData(struct HttpRequestHdr* hdr, const char* str)
00783 {
00784   char* pos = strchr(str, ':');
00785   char* datpos = pos+1;
00786   while(isspace((int) *datpos))
00787     datpos++;
00788 
00789   if (hdr == NULL) return -2;
00790 
00791   if (pos - str < (int)strlen(str))
00792   {
00793 //    NOT IMPLEMENTED
00794 //    if (strncmp(str,"Authorisation:",pos-str) == 0)
00795 //    { }
00796 //    else
00797     if (strncmp(str,"From:",pos-str) == 0)
00798     {
00799       hdr->from = (char*)pd_malloc(strlen(str)-(datpos-str)+1);
00800       strcpy(hdr->from, datpos);
00801     }
00802     else if (strncmp(str,"If-Modified-Since:",pos-str) == 0)
00803     {
00804       hdr->if_mod_since = strToTimet(pos+1);
00805     }
00806     else if (strncmp(str,"Referer:",pos-str) == 0)
00807     {
00808       hdr->referer = resolvURI(pos+1);
00809     }
00810     else if (strncmp(str,"User-Agent:",pos-str) == 0)
00811     {
00812       hdr->usr_agent = (char*)pd_malloc(strlen(str)-(datpos-str)+1);
00813       strcpy(hdr->usr_agent, datpos);
00814     }
00815     else if (strncmp(str,"Host:",pos-str) == 0)
00816     {
00817       struct Uri tmpuri;
00818       char* http = "http://";
00819       size_t len_http = 7; //= strlen("http://");
00820       char* tmp = pd_malloc(strlen(str)-(datpos-str)+len_http+1);
00821 
00822       strcpy(tmp, http);
00823       strcat(tmp, datpos);
00824 
00825       tmpuri = resolvURI(tmp);
00826 
00827       if (tmpuri.valid)
00828       {
00829         if (hdr->uri.server != NULL)
00830           pd_free(hdr->uri.server);
00831         hdr->uri.server = tmpuri.server;
00832         hdr->uri.port = tmpuri.port;
00833       }
00834       
00835       pd_free(tmpuri.path);
00836       pd_free(tmp);
00837     }
00838   }
00839   return 0;
00840 }
00841 
00843 const char* getStatusAsText(HttpProtHandler this)
00844 {
00845   switch(this->status)
00846   {
00847   case(200): return "OK";
00848   case(201): return "Created";
00849   case(202): return "Accepted";
00850   case(204): return "No Content";
00851   case(301): return "Moved Permanently";
00852   case(302): return "Moved Temporarily";
00853   case(304): return "Not Modified";
00854   case(400): return "Bad Request";
00855   case(401): return "Unauthorized";
00856   case(403): return "Forbidden";
00857   case(404): return "Not Found";
00858   case(500): return "Internal Server Error";
00859   case(501): return "Not Implemented";
00860   case(502): return "Bad Gateway";
00861   case(503): return "Service Unavailable";
00862   default:   return "Unknown";
00863   }
00864 }
00865 
00867 struct Uri resolvURI(const char* pstr)
00868 {
00869   struct Uri uri;
00870   size_t pos = 0;
00871   size_t len_http = 7; // = strlen("http://");
00872 
00873   //"remove" leading space
00874   int offset = 0;
00875   //temporary string!
00876   char* str = (char*)pd_malloc(strlen(pstr)+1);
00877 
00878   uri.valid = true;
00879 
00880   while (isspace((int) *(pstr+offset)))
00881     offset++;
00882   strcpy(str, pstr+offset);
00883   //and go on with temporary string "str"
00884 
00885   if (strncmp(str, "http://", len_http) == 0)
00886   { //absolute path found
00887     pos += len_http;
00888     //walk thru chars until a non valid one (domain) is found
00889     while ((isalnum((int) *(str+pos))
00890         || *(str+pos) == '.' || *(str+pos) == '_' || *(str+pos) == '-')
00891         && pos < strlen(str))
00892       pos++;
00893 
00894     if (pos == strlen(str))
00895     { // found the end, no url given, no port
00896       uri.path = pd_malloc(2);
00897       strcpy(uri.path, "/");
00898       uri.server = pd_malloc(strlen(str)-len_http);
00899       strcpy(uri.server, str+len_http);
00900       uri.port = 0;
00901     }
00902     else if (*(str+pos) == ':')
00903     { //found a port, check the following port
00904       size_t oldpos = pos++;
00905 
00906       //chk for port
00907       while(isdigit((int) *(str+pos)) && pos < strlen(str))
00908         pos++;
00909 
00910       if (pos == strlen(str))
00911       { // found the end, no url, but port
00912         uri.path = pd_malloc(2);
00913         strcpy(uri.path, "/");
00914         uri.server = pd_malloc(oldpos-len_http+1);
00915         strncpy(uri.server, str+len_http, oldpos-len_http);
00916         *(uri.server+oldpos-len_http-1+1) = '\0';
00917       }
00918       else
00919       { //found port, url and server
00920         uri.path = pd_malloc(strlen(str)-pos+1);
00921         strcpy(uri.path, str+pos);
00922 
00923         uri.server = pd_malloc(oldpos-len_http+1);
00924         strncpy(uri.server, str+len_http, oldpos-len_http);
00925         *(uri.server+oldpos-len_http-1+1) = '\0';
00926       }
00927 
00928       //only ':' without given port (-> stdport is used)
00929       if (pos == oldpos+1)
00930         uri.port = 0;
00931       else
00932       {   //get the port
00933         char* tmp = pd_malloc(pos - oldpos);
00934 
00935         strncpy(tmp, str+oldpos+1, pos-oldpos-1);
00936         *(tmp+pos-oldpos-1) = '\0';
00937         uri.port = atoi(tmp);
00938         pd_free(tmp);
00939 
00940         if (uri.port < 1 || uri.port > 65535)
00941           uri.port = 0;
00942       }
00943     }
00944     else
00945     { // found no port, but server and url
00946       uri.path = pd_malloc(strlen(str)-pos+1);
00947       strncpy(uri.path, str+pos, strlen(str)-pos);
00948       *(uri.path+strlen(str)-pos+1) = '\0';
00949       if (pos == len_http )
00950         uri.server = NULL;
00951       else
00952       {
00953         uri.server = pd_malloc(pos-len_http);
00954         strncpy(uri.server, str+len_http, pos-len_http);
00955         *(uri.server+pos-len_http) = '\0';
00956       }
00957       uri.port = 0;
00958     }
00959   }
00960   else
00961   { //relativepath
00962     uri.path = pd_malloc(strlen(str)+1);
00963     strcpy(uri.path, str);
00964     uri.server = NULL;
00965     uri.port = 0;
00966   }
00967   pd_free(str);
00968   return uri;
00969 }
00970 
00972 int err2Status(int err)
00973 {
00974   switch (err)
00975   {   
00976     case(ENOENT):
00977     case(ENOTDIR):
00978       //file not found
00979       return 404;
00980     case(EACCES):
00981       //Acces Denied
00982       return 403;
00983     case(EIO):
00984     default:
00985       //internal server error
00986       return 500;
00987   }
00988 }

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