processor.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C), 2000-2002 by Contributors to the monit codebase. 
00003  * All Rights Reserved.
00004  *
00005  * This program is free software; you can redistribute it and/or
00006  * modify it under the terms of the GNU General Public License as
00007  * published by the Free Software Foundation; either version 2 of the
00008  * License, or (at your option) any later version.
00009  *
00010  * This program is distributed in the hope that it will be useful, but
00011  * WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013  * General Public License for more details.
00014  * 
00015  * You should have received a copy of the GNU General Public License
00016  * along with this program; if not, write to the Free Software Foundation,
00017  * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
00018  */
00019 
00020 #include <config.h>
00021 
00022 #include <stdio.h>
00023 #include <stdlib.h>
00024 #include <stdarg.h>
00025 #include <errno.h>
00026 
00027 #ifdef HAVE_SYS_TYPES_H
00028 #include <sys/types.h>
00029 #endif
00030 
00031 #include <sys/socket.h>
00032 #include <time.h>
00033 #include <setjmp.h>
00034 
00035 #ifdef HAVE_STRING_H
00036 #include <string.h>
00037 #endif
00038 
00039 #ifdef HAVE_UNISTD_H
00040 #include <unistd.h>
00041 #endif
00042 
00043 #ifdef HAVE_LIMITS_H
00044 #include <limits.h>
00045 #endif
00046 
00047 #include "processor.h"
00048 #include "base64.h"
00049 
00050 #define REQUEST   1
00051 #define RESPONSE  2
00052 #define HEADER    3
00053 #define PARAM     4
00054 
00055 /* Private variables */
00056 static sigjmp_buf timeout;
00057 
00058 /* Private prototypes */
00059 static void do_service(RequestWrapper);
00060 static void send_response(HttpResponse);
00061 static char *get_date();
00062 static char *get_server(); 
00063 static HttpRequest create_HttpRequest(RequestWrapper);
00064 static HttpResponse create_HttpResponse(RequestWrapper);
00065 static void create_headers(HttpRequest);
00066 static int create_parameters(HttpRequest req);
00067 static void reset_response(HttpResponse res);
00068 static int is_authenticated(HttpRequest, HttpResponse);
00069 static int basic_authenticate(HttpRequest);
00070 static void done(HttpRequest, HttpResponse);
00071 static void destroy_HttpRequest(HttpRequest);
00072 static void destroy_HttpResponse(HttpResponse);
00073 static void destroy_entry(void *);
00074 static void internal_error(int, int, char *);
00075 static HttpParameter parse_parameters(char *);
00076 static int do_timeout(int);
00077 static void request_timeout(int);
00078 
00079 
00112 /* ------------------------------------------------------------------- Entry */
00113 
00114 
00121 void *http_processor(void *wrapper) {
00122   
00123   RequestWrapper W= wrapper;
00124 
00125   if (do_timeout(W->socket))
00126       goto shutdown;
00127     
00128   do_service(W);
00129 
00130   shutdown:
00131   alarm(0);
00132   destroy_wrapper(W);
00133 
00134   return NULL;
00135   
00136 }
00137 
00138 
00144 void add_Impl(void *doGetFunc, void *doPostFunc) {
00145 
00146   Impl.doGet= doGetFunc;
00147   Impl.doPost= doPostFunc;
00148 
00149 }
00150 
00151 
00152 /* ------------------------------------------------------------------ Public */
00153 
00154 
00161 void send_error(HttpResponse res, int code, char *msg) {
00162 
00163   char *err= get_status_string(code);
00164   char *server= get_server();
00165   
00166   reset_response(res);
00167   set_content_type(res, "text/html");
00168   set_status(res, code, err);
00169   out_print(res,
00170        "<html><head><title>%d %s</title></head>"\
00171        "<body bgcolor=#FFFFFF><h2>%s</h2>%s<p>"\
00172        "<hr><a href='%s'><font size=-1>%s</font></a>"\
00173        "</body></html>\r\n",
00174         code, err, err, msg?msg:"", SERVER_URL, server);
00175   free(err);
00176   free(server);
00177        
00178 }
00179 
00180 
00187 void send_redirect(HttpResponse res, char *location) {
00188 
00189   char *string= get_status_string(SC_MOVED_TEMPORARILY);
00190   reset_response(res);
00191   set_status(res, SC_MOVED_TEMPORARILY, string);
00192   set_header(res, "Location", location);
00193   free(string);
00194 
00195 }
00196 
00197 
00212 void out_print(HttpResponse res, const char *format, ...) {
00213 
00214   if ( format ) {
00215     
00216     int n= 0;
00217     ssize_t need= 0;
00218     ssize_t have= 0;
00219     int size= RES_STRLEN;
00220     char *string= xmalloc(size);
00221     va_list ap;
00222 
00223     /* Ripped from the Linux vsnprintf man page */
00224     while (1) {
00225       
00226       va_start(ap, format);
00227       n= vsnprintf(string, size, format, ap);
00228       va_end(ap);
00229       
00230       if (n > -1 && n < size) {
00231     
00232       break;
00233 
00234       }
00235       
00236       if (n > -1) {
00237     
00238       size= n+1;
00239 
00240       } else {
00241     
00242       size*= 2;
00243 
00244       }
00245       
00246       string= xresize(string, size);
00247       
00248     }
00249 
00250     /* Check for possible buffersize overflow and abort if detected */
00251     if ( (float)((float)(sizeof(char)*(res->bufsize + RES_STRLEN + n + 1))
00252          > SSIZE_MAX) ) {
00253       
00254       log("out_print: Possible http response buffer overflow detected. "
00255       "aborting \n");
00256       exit(1);
00257       
00258     }
00259 
00260     have= res->bufsize - res->bufused;
00261     need= sizeof(char)*( n + 1); 
00262       
00263     if ( have <= need ) {
00264       
00265       /* Geometrical expand the outputbuffer size */ 
00266       res->outputbuffer=
00267       xresize(res->outputbuffer,(res->bufsize + need + RES_STRLEN));
00268       
00269       res->bufsize+= (need + RES_STRLEN);
00270       
00271       if ( !res->bufused ) {
00272     
00273       memset(res->outputbuffer, 0, res->bufsize);
00274 
00275       }
00276       
00277       res->bufused+= need;
00278       
00279     } else {
00280       
00281       res->bufused+= need;
00282       
00283     }
00284     
00285     strcat(res->outputbuffer, string);
00286     
00287     free(string);
00288     
00289   }
00290   
00291 }
00292 
00293 
00298 void destroy_wrapper(RequestWrapper w) {
00299   
00300   if ( w && w->inetaddr ) {
00301 
00302     free(w->inetaddr->remote_host);
00303     free(w->inetaddr->local_host);
00304     free(w->inetaddr);
00305 
00306   }
00307 
00308   close_socket(w->socket);
00309 
00310   free(w);
00311 
00312 }
00313 
00314 
00315 /* -------------------------------------------------------------- Properties */
00316 
00317 
00325 void set_header(HttpResponse res, char *name, char *value) {
00326 
00327   HttpHeader h= NEW(h);
00328   
00329   h->name= xstrdup(name);
00330   h->value= xstrdup(value);
00331   
00332   if ( res->headers ) {
00333     
00334     HttpHeader n, p;
00335     
00336     for ( n= p= res->headers; p; n= p, p= p->next) {
00337       
00338       if ( !strcasecmp(p->name, name) ) {
00339     
00340     free(p->value);
00341     p->value= xstrdup(value);
00342     destroy_entry(h);
00343     return;
00344     
00345       }
00346       
00347     }
00348     
00349     n->next= h;
00350     
00351   } else {
00352     
00353     res->headers= h;
00354     
00355   }
00356 
00357 }
00358 
00359 
00366 void set_status(HttpResponse res, int code, char *msg) {
00367   
00368   res->status= code;
00369   free(res->status_msg);
00370   res->status_msg= xstrdup(msg);
00371   
00372 }
00373 
00374 
00380 void set_content_type(HttpResponse res, char *mime) {
00381 
00382   set_header(res, "Content-Type", mime);
00383 
00384 }
00385 
00386 
00393 char *get_header(HttpRequest req, const char *name) {
00394 
00395   HttpHeader p;
00396 
00397   for ( p= req->headers; p; p= p->next) {
00398     
00399     if ( !strcasecmp(p->name, name) ) {
00400       
00401     return xstrdup(p->value);
00402 
00403     }
00404     
00405   }
00406 
00407   return NULL;
00408 
00409 }
00410 
00411 
00418 char *get_parameter(HttpRequest req, const char *name) {
00419 
00420   HttpParameter p;
00421 
00422   for ( p= req->params; p; p= p->next) {
00423     
00424     if ( !strcasecmp(p->name, name) ) {
00425       
00426     return xstrdup(p->value);
00427 
00428     }
00429     
00430   }
00431 
00432   return NULL;
00433 
00434 }
00435 
00436 
00444 char *get_headers(HttpResponse res) {
00445 
00446   HttpHeader p;
00447   char buf[RES_STRLEN];
00448   char *b= buf;
00449 
00450   for ( p= res->headers; p; p= p->next) {
00451     
00452     b+= sprintf(b, "%s: %s\r\n", p->name, p->value);
00453     
00454   }
00455   
00456   return buf[0]?xstrdup(buf):NULL;
00457 
00458 }
00459 
00460 
00468 char *get_status_string(int status) {
00469 
00470   switch (status) {
00471   case SC_OK:
00472       return xstrdup("OK");
00473   case SC_ACCEPTED:
00474       return xstrdup("Accepted");
00475   case SC_BAD_GATEWAY:
00476       return xstrdup("Bad Gateway");
00477   case SC_BAD_REQUEST:
00478       return xstrdup("Bad Request");
00479   case SC_CONFLICT:
00480       return xstrdup("Conflict");
00481   case SC_CONTINUE:
00482       return xstrdup("Continue");
00483   case SC_CREATED:
00484       return xstrdup("Created");
00485   case SC_EXPECTATION_FAILED:
00486       return xstrdup("Expectation Failed");
00487   case SC_FORBIDDEN:
00488       return xstrdup("Forbidden");
00489   case SC_GATEWAY_TIMEOUT:
00490       return xstrdup("Gateway Timeout");
00491   case SC_GONE:
00492       return xstrdup("Gone");
00493   case SC_VERSION_NOT_SUPPORTED:
00494       return xstrdup("HTTP Version Not Supported");
00495   case SC_INTERNAL_SERVER_ERROR:
00496       return xstrdup("Internal Server Error");
00497   case SC_LENGTH_REQUIRED:
00498       return xstrdup("Length Required");
00499   case SC_METHOD_NOT_ALLOWED:
00500       return xstrdup("Method Not Allowed");
00501   case SC_MOVED_PERMANENTLY:
00502       return xstrdup("Moved Permanently");
00503   case SC_MOVED_TEMPORARILY:
00504       return xstrdup("Moved Temporarily");
00505   case SC_MULTIPLE_CHOICES:
00506       return xstrdup("Multiple Choices");
00507   case SC_NO_CONTENT:
00508       return xstrdup("No Content");
00509   case SC_NON_AUTHORITATIVE:
00510       return xstrdup("Non-Authoritative Information");
00511   case SC_NOT_ACCEPTABLE:
00512       return xstrdup("Not Acceptable");
00513   case SC_NOT_FOUND:
00514       return xstrdup("Not Found");
00515   case SC_NOT_IMPLEMENTED:
00516       return xstrdup("Not Implemented");
00517   case SC_NOT_MODIFIED:
00518       return xstrdup("Not Modified");
00519   case SC_PARTIAL_CONTENT:
00520       return xstrdup("Partial Content");
00521   case SC_PAYMENT_REQUIRED:
00522       return xstrdup("Payment Required");
00523   case SC_PRECONDITION_FAILED:
00524       return xstrdup("Precondition Failed");
00525   case SC_PROXY_AUTHENTICATION_REQUIRED:
00526       return xstrdup("Proxy Authentication Required");
00527   case SC_REQUEST_ENTITY_TOO_LARGE:
00528       return xstrdup("Request Entity Too Large");
00529   case SC_REQUEST_TIMEOUT:
00530       return xstrdup("Request Timeout");
00531   case SC_REQUEST_URI_TOO_LARGE:
00532       return xstrdup("Request URI Too Large");
00533   case SC_RANGE_NOT_SATISFIABLE:
00534       return xstrdup("Requested Range Not Satisfiable");
00535   case SC_RESET_CONTENT:
00536       return xstrdup("Reset Content");
00537   case SC_SEE_OTHER:
00538       return xstrdup("See Other");
00539   case SC_SERVICE_UNAVAILABLE:
00540       return xstrdup("Service Unavailable");
00541   case SC_SWITCHING_PROTOCOLS:
00542       return xstrdup("Switching Protocols");
00543   case SC_UNAUTHORIZED:
00544       return xstrdup("Unauthorized");
00545   case SC_UNSUPPORTED_MEDIA_TYPE:
00546       return xstrdup("Unsupported Media Type");
00547   case SC_USE_PROXY:
00548       return xstrdup("Use Proxy");
00549   default: {
00550      char buf[STRLEN];
00551      snprintf(buf, STRLEN, "HTTP Response Status %d", status);
00552      return xstrdup(buf);
00553     } 
00554   }
00555 
00556 }
00557 
00558 
00559 /* ----------------------------------------------------------------- Private */
00560 
00561 
00566 static void do_service(RequestWrapper w) {
00567 
00568   volatile HttpResponse res= create_HttpResponse(w);
00569   volatile HttpRequest req= create_HttpRequest(w);
00570   
00571   if ( res && req ) {
00572     
00573     if ( is_authenticated(req, res) ) {
00574       
00575       if ( !strcmp(req->method, METHOD_GET) ) {
00576     
00577     Impl.doGet(req, res);
00578     
00579       }
00580       else if ( !strcmp(req->method, METHOD_POST) ) {
00581     
00582     Impl.doPost(req, res);
00583     
00584       }
00585       else {
00586     
00587     send_error(res, SC_NOT_IMPLEMENTED, "Method not implemented");
00588     
00589       }
00590 
00591     }
00592     
00593     if ( check_socket(w->socket) ) {
00594       
00595       send_response(res);
00596       
00597     }
00598     
00599   }
00600 
00601   done(req, res);
00602   
00603 }
00604 
00605 
00609 static char *get_date() {
00610 
00611   char date[STRLEN];
00612   time_t now;
00613   
00614   time(&now);
00615   
00616   if ( !strftime(date, STRLEN, DATEFMT, gmtime(&now)) ) {
00617     
00618       memset(date, 0, STRLEN);
00619 
00620   }
00621   
00622   return xstrdup(date);
00623   
00624 }
00625 
00626 
00630 static char *get_server() {
00631 
00632   char server[STRLEN];
00633   snprintf(server, STRLEN, "%s %s", SERVER_NAME, SERVER_VERSION);
00634   
00635   return xstrdup(server);
00636   
00637 }
00638 
00639 
00644 static void send_response(HttpResponse res) {
00645 
00646   if ( !res->is_committed ) {
00647     
00648     FILE *out= res->outputstream;
00649     char *date= get_date();
00650     char *server= get_server();
00651     char *headers= get_headers(res);
00652     int  len= res->bufused?strlen(res->outputbuffer):0;
00653     
00654     fprintf(out, "%s %d %s\r\n", res->protocol, res->status, res->status_msg);
00655     fprintf(out, "Date: %s\r\n", date);
00656     fprintf(out, "Server: %s\r\n", server);
00657     fprintf(out, "Content-length: %d\r\n", len);
00658     fprintf(out, "Connection: close\r\n");
00659     if ( headers ) fprintf(out, "%s", headers);
00660     fprintf(out, "\r\n\r\n");
00661     
00662     if ( res->bufused ) fprintf(out, "%s", res->outputbuffer);
00663     
00664     free(headers);
00665     free(date);
00666     free(server);
00667     
00668   }
00669 
00670 }
00671 
00672 
00673 /* --------------------------------------------------------------- Factories */
00674 
00675 
00679 static HttpRequest create_HttpRequest(RequestWrapper W) {
00680 
00681   char line[REQ_STRLEN];
00682   char method[STRLEN];
00683   char url[REQ_STRLEN];
00684   char protocol[STRLEN]; 
00685   HttpRequest req;
00686   FILE *in= fdopen(dup(W->socket), "r");
00687 
00688   if ( in == NULL ) {
00689     
00690     internal_error(W->socket, SC_INTERNAL_SERVER_ERROR,
00691            "Cannot create inputstream");
00692     return NULL;
00693     
00694   }
00695   
00696   if ( fgets(line, sizeof(line), in) == NULL ) {
00697     
00698     internal_error(W->socket, SC_BAD_REQUEST, "No request found");
00699     fclose(in);
00700     return NULL;
00701     
00702   }
00703   
00704   if ( sscanf(line, "%s %s HTTP/%3[1.0]", method, url, protocol) != 3 ) {
00705     
00706     internal_error(W->socket, SC_BAD_REQUEST, "Cannot parse request");
00707     fclose(in);
00708     return NULL;
00709     
00710   }
00711 
00712   req= NEW(req);
00713   unescape_url(url);
00714   chomp(protocol);
00715   req->method= xstrdup(method);
00716   req->url= xstrdup(url);
00717   req->protocol= xstrdup(protocol); 
00718   req->inputstream= in;
00719   req->inetaddr= W->inetaddr;
00720 
00721   create_headers(req);
00722   
00723   if ( !create_parameters(req) ) {
00724     
00725     internal_error(W->socket, SC_BAD_REQUEST,
00726     "Cannot parse Request parameters");
00727     fclose(in);
00728     return NULL;
00729     
00730   }
00731     
00732   return req;
00733   
00734 }
00735 
00736 
00741 static HttpResponse create_HttpResponse(RequestWrapper W) {
00742   
00743   HttpResponse res;
00744   FILE *out= fdopen(dup(W->socket), "w");
00745 
00746   if ( out == NULL ) {
00747     
00748     internal_error(W->socket, SC_INTERNAL_SERVER_ERROR,
00749            "Cannot create outputstream");
00750     return NULL;
00751     
00752   }
00753   
00754   res= NEW(res);
00755   res->protocol= xstrdup(SERVER_PROTOCOL);
00756   res->status= 200;
00757   res->status_msg= get_status_string(SC_OK);
00758   res->outputstream= out;
00759   res->outputbuffer= NULL;
00760   res->bufsize= 0;
00761   res->bufused= 0;
00762   res->is_committed= FALSE;
00763   
00764   return res;
00765   
00766 }
00767 
00768 
00772 static void create_headers(HttpRequest req) {
00773 
00774   char line[REQ_STRLEN];
00775   char *value;
00776   HttpHeader p;
00777   HttpHeader header;
00778   
00779   while ( NULL != fgets(line, sizeof(line), req->inputstream) ) {
00780     
00781     if ( !strcmp(line, "\r\n") || !strcmp(line, "\n") )
00782     break;
00783     
00784     if( NULL != (value= strchr(line, ':')) ) {
00785       
00786       header= NEW(header);
00787       *value++= '\0';
00788       trim(line);
00789       trim(value);
00790       chomp(value);
00791       header->name= xstrdup(line);
00792       header->value= xstrdup(value);
00793       
00794       if ( req->headers ) {
00795     
00796     for ( p= req->headers; p->next; p= p->next)
00797         /* Empty */;
00798     p->next= header;
00799     
00800       } else {
00801     
00802     req->headers= header;
00803     
00804       }
00805       
00806     }
00807     
00808   }
00809   
00810 }
00811 
00812 
00817 static int create_parameters(HttpRequest req) {
00818 
00819   char *query_string= NULL;
00820   int alloc= FALSE;
00821 
00822   if ( !strcmp(req->method, METHOD_POST) ) {
00823     
00824     int len; char *l= get_header(req, "Content-Length");
00825     
00826     if ( l && (len= atoi(l)) ) {
00827       
00828       query_string= xmalloc(sizeof(char) * (len + 1));
00829       
00830       if ( fgets(query_string, (sizeof(char)*(len+1)),
00831          req->inputstream) == NULL ) {
00832     
00833     free(query_string);
00834     return FALSE;
00835     
00836       }
00837       
00838       alloc= TRUE;
00839       
00840     }
00841     
00842   } else if ( !strcmp(req->method, METHOD_GET) ) {
00843     
00844     char *p;
00845     
00846     if( NULL != (p= strchr(req->url, '?')) ) {
00847       
00848       *p++= '\0';
00849       query_string= p;
00850       
00851     }
00852     
00853   }
00854   
00855   if ( query_string ) {
00856     
00857     char *p;
00858     
00859     if( NULL != (p= strchr(query_string, '/')) ) {
00860       
00861       *p++= '\0';
00862       req->pathinfo= p;
00863       
00864     }
00865     
00866     req->params= parse_parameters(query_string);
00867     
00868   }
00869 
00870   if ( alloc ) free(query_string);
00871   
00872   return TRUE;
00873   
00874 }
00875 
00876 
00877 
00878 /* ----------------------------------------------------------------- Cleanup */
00879 
00880 
00884 static void reset_response(HttpResponse res) {
00885 
00886   if ( res->headers ) destroy_entry(res->headers);
00887   memset(res->outputbuffer, 0, res->bufsize);
00888   res->headers= NULL; /* Release Pragma */
00889   
00890 }
00891 
00892 
00896 static void done(HttpRequest req, HttpResponse res) {
00897 
00898   destroy_HttpRequest(req);
00899   destroy_HttpResponse(res);
00900 
00901 }
00902 
00903 
00907 static void destroy_HttpRequest(HttpRequest req) {
00908 
00909   if ( req ) {
00910     
00911     if ( req->inputstream ) fclose(req->inputstream);
00912     free(req->method);
00913     free(req->url); /* req->pathinfo is freed with url */
00914     free(req->protocol);
00915     if ( req->headers ) destroy_entry(req->headers);
00916     if ( req->params ) destroy_entry(req->params);
00917     free(req);
00918     
00919   }
00920   
00921 }
00922 
00923 
00927 static void destroy_HttpResponse(HttpResponse res) {
00928 
00929   if ( res ) {
00930     
00931     if ( res->outputstream ) fclose(res->outputstream);
00932     free(res->protocol);
00933     free(res->status_msg);
00934     free(res->outputbuffer);
00935     if ( res->headers) destroy_entry(res->headers);
00936     free(res);
00937     
00938   }
00939   
00940 }
00941 
00942 
00947 static void destroy_entry(void *p) {
00948   
00949   struct entry *h= p; 
00950   
00951   if ( h->next ) {
00952     
00953     destroy_entry(h->next);
00954     
00955   }
00956 
00957   free(h->name);
00958   free(h->value);
00959   free(h);
00960  
00961 }
00962 
00963 
00964 /* ----------------------------------------------------- Checkers/Validators */
00965 
00966 
00971 static int do_timeout(int client) {
00972 
00973   set_alarm_handler(request_timeout);
00974   
00975   alarm(REQUEST_TIMEOUT);
00976   
00977   if ( sigsetjmp(timeout, TRUE) ) {
00978     
00979     internal_error(client, SC_REQUEST_TIMEOUT,
00980            "Time out when handling the Request");
00981     
00982     return TRUE;
00983     
00984   }
00985   
00986   return FALSE;
00987   
00988 }
00989 
00990 
00994 static int is_authenticated(HttpRequest req, HttpResponse res) {
00995 
00996   if ( Run.Auth.defined ) {
00997 
00998     if ( ! basic_authenticate(req) ) {
00999       
01000       send_error(res, SC_UNAUTHORIZED,
01001          "You are <b>not</b> authorized to access <i>monit</i>. "
01002          "Either you supplied the wrong credentials (e.g. bad "
01003          "password), or your browser doesn't understand how to supply "
01004          "the credentials required");
01005       set_header(res, "WWW-Authenticate", "Basic realm=\"monit\"");
01006       
01007       return FALSE;
01008       
01009     }
01010 
01011   }
01012 
01013   return TRUE;
01014 
01015 }
01016 
01017 
01022 static int basic_authenticate(HttpRequest req) {
01023 
01024   int rv= FALSE;
01025   char *credentials= get_header(req, "Authorization");
01026 
01027   if ( credentials ) {
01028 
01029     unsigned char *cr= xcalloc(sizeof(unsigned char), strlen(credentials)+1);
01030 
01031     if ( decode_base64(cr, strchr(credentials, ' ')) ) {
01032 
01033       char buf[STRLEN];
01034 
01035       snprintf(buf, STRLEN, "%s:%s", Run.Auth.uname, Run.Auth.passwd);
01036       
01037       if ( !strncmp(cr, buf, strlen(buf)) ) {
01038       
01039       rv= TRUE;
01040       
01041       }
01042     
01043     }
01044     
01045     free(cr);
01046     free(credentials);
01047 
01048   }
01049   
01050   return rv;
01051   
01052 }
01053 
01054 
01055 /* --------------------------------------------------------------- Utilities */
01056 
01057 
01063 static void internal_error(int client, int status, char *msg) {
01064 
01065   char response[RES_STRLEN];
01066   char *server= get_server();
01067   char *date= get_date();
01068   char *status_msg= get_status_string(status);
01069 
01070   snprintf(response, RES_STRLEN,
01071        "%s %d %s\r\n"
01072        "Date: %s\r\n"
01073        "Server: %s\r\n"
01074        "Content-Type: text/html\r\n"
01075        "Connection: close\r\n"
01076        "\r\n"
01077        "<html><head><title>%s</title></head>"
01078        "<body bgcolor=#FFFFFF><h2>%s</h2>%s<p>"
01079        "<hr><a href='%s'><font size=-1>%s</font></a>"
01080        "</body></html>\r\n",
01081        SERVER_PROTOCOL, status, status_msg, date, server,
01082        status_msg, status_msg, msg, SERVER_URL, server);
01083   sock_send(client, response, strlen(response), 0);
01084   free(server);
01085   free(date);
01086   free(status_msg);
01087   
01088 }
01089 
01090 
01095 static HttpParameter parse_parameters(char *query_string) {
01096 
01097   HttpParameter head= NULL;
01098   int controller= 1000;
01099   
01100   while ( query_string[0] && controller-- ) {
01101     
01102     HttpParameter p= NEW(p);
01103     p->value= makeword(query_string,'&');
01104     p->name= makeword(p->value,'=');
01105     plustospace(p->value);
01106     unescape_url(p->value);
01107     plustospace(p->name);
01108     unescape_url(p->name);
01109     p->next= head;
01110     head= p;
01111     
01112   }
01113 
01114   return head;
01115   
01116 }
01117 
01118 
01122 static void request_timeout(int sig) {
01123 
01124   siglongjmp(timeout, TRUE);
01125   
01126 }
01127