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 #include "ssl.h"
00050 
00051 #define REQUEST   1
00052 #define RESPONSE  2
00053 #define HEADER    3
00054 #define PARAM     4
00055 
00056 /* Private variables */
00057 extern ssl_server_connection * mySSLServerConnection;
00058 
00059 /* Private prototypes */
00060 static void do_service(RequestWrapper);
00061 static void send_response(HttpResponse);
00062 static char *get_date();
00063 static char *get_server(); 
00064 static HttpRequest create_HttpRequest(RequestWrapper);
00065 static HttpResponse create_HttpResponse(RequestWrapper);
00066 static void create_headers(HttpRequest);
00067 static int create_parameters(HttpRequest req);
00068 static void reset_response(HttpResponse res);
00069 static int is_authenticated(HttpRequest, HttpResponse);
00070 static int basic_authenticate(HttpRequest);
00071 static void done(HttpRequest, HttpResponse);
00072 static void destroy_HttpRequest(HttpRequest);
00073 static void destroy_HttpResponse(HttpResponse);
00074 static void destroy_entry(void *);
00075 static void internal_error(int, int, char *);
00076 static void internal_error_ssl(ssl_connection *, int, char *);
00077 static HttpParameter parse_parameters(char *);
00078 static int is_available(int);
00079 
00080 
00114 /* ------------------------------------------------------------------- Entry */
00115 
00116 
00123 void *http_processor(void *wrapper) {
00124   
00125   RequestWrapper W= wrapper;
00126 
00127   if(! is_available(W->socket)) {
00128     
00129     internal_error(W->socket, SC_REQUEST_TIMEOUT,
00130            "Time out when handling the Request");
00131     goto shutdown;
00132     
00133   }
00134   do_service(W);
00135 
00136   shutdown:
00137   destroy_wrapper(W);
00138 
00139   return NULL;
00140   
00141 }
00142 
00143 
00149 void add_Impl(void *doGetFunc, void *doPostFunc) {
00150 
00151   Impl.doGet= doGetFunc;
00152   Impl.doPost= doPostFunc;
00153 
00154 }
00155 
00156 
00157 /* ------------------------------------------------------------------ Public */
00158 
00159 
00166 void send_error(HttpResponse res, int code, char *msg) {
00167 
00168   char *err= get_status_string(code);
00169   char *server= get_server();
00170   
00171   reset_response(res);
00172   set_content_type(res, "text/html");
00173   set_status(res, code, err);
00174   out_print(res,
00175        "<html><head><title>%d %s</title></head>"\
00176        "<body bgcolor=#FFFFFF><h2>%s</h2>%s<p>"\
00177        "<hr><a href='%s'><font size=-1>%s</font></a>"\
00178        "</body></html>\r\n",
00179         code, err, err, msg?msg:"", SERVER_URL, server);
00180   free(err);
00181   free(server);
00182        
00183 }
00184 
00185 
00192 void send_redirect(HttpResponse res, char *location) {
00193 
00194   char *string= get_status_string(SC_MOVED_TEMPORARILY);
00195   reset_response(res);
00196   set_status(res, SC_MOVED_TEMPORARILY, string);
00197   set_header(res, "Location", location);
00198   free(string);
00199 
00200 }
00201 
00202 
00217 void out_print(HttpResponse res, const char *format, ...) {
00218 
00219   if ( format ) {
00220     
00221     int n= 0;
00222     ssize_t need= 0;
00223     ssize_t have= 0;
00224     int size= RES_STRLEN;
00225     char *string= xmalloc(size);
00226     va_list ap;
00227 
00228     /* Ripped from the Linux vsnprintf man page */
00229     while (1) {
00230       
00231       va_start(ap, format);
00232       n= vsnprintf(string, size, format, ap);
00233       va_end(ap);
00234       
00235       if (n > -1 && n < size) {
00236     
00237       break;
00238 
00239       }
00240       
00241       if (n > -1) {
00242     
00243       size= n+1;
00244 
00245       } else {
00246     
00247       size*= 2;
00248 
00249       }
00250       
00251       string= xresize(string, size);
00252       
00253     }
00254 
00255     /* Check for possible buffersize overflow and abort if detected */
00256     if ( (float)((float)(sizeof(char)*(res->bufsize + RES_STRLEN + n + 1))
00257          > SSIZE_MAX) ) {
00258       
00259       log("out_print: Possible http response buffer overflow detected. "
00260       "aborting \n");
00261       exit(1);
00262       
00263     }
00264 
00265     have= res->bufsize - res->bufused;
00266     need= sizeof(char)*( n + 1); 
00267       
00268     if ( have <= need ) {
00269       
00270       /* Geometrical expand the outputbuffer size */ 
00271       res->outputbuffer=
00272       xresize(res->outputbuffer,(res->bufsize + need + RES_STRLEN));
00273       
00274       res->bufsize+= (need + RES_STRLEN);
00275       
00276       if ( !res->bufused ) {
00277     
00278       memset(res->outputbuffer, 0, res->bufsize);
00279 
00280       }
00281       
00282       res->bufused+= need;
00283       
00284     } else {
00285       
00286       res->bufused+= need;
00287       
00288     }
00289     
00290     strcat(res->outputbuffer, string);
00291     
00292     free(string);
00293     
00294   }
00295   
00296 }
00297 
00298 
00303 void destroy_wrapper(RequestWrapper w) {
00304   
00305   if ( w && w->inetaddr ) {
00306 
00307     free(w->inetaddr->remote_host);
00308     free(w->inetaddr->local_host);
00309     free(w->inetaddr);
00310 
00311   }
00312 
00313   if ( Run.httpdssl ) {
00314 
00315     close_accepted_ssl_socket(mySSLServerConnection, w->ssl);
00316 
00317   } else {
00318 
00319     close_socket(w->socket);
00320 
00321   }
00322 
00323   free(w);
00324 
00325 }
00326 
00327 
00328 /* -------------------------------------------------------------- Properties */
00329 
00330 
00338 void set_header(HttpResponse res, char *name, char *value) {
00339 
00340   HttpHeader h= NEW(h);
00341   
00342   h->name= xstrdup(name);
00343   h->value= xstrdup(value);
00344   
00345   if ( res->headers ) {
00346     
00347     HttpHeader n, p;
00348     
00349     for ( n= p= res->headers; p; n= p, p= p->next) {
00350       
00351       if ( !strcasecmp(p->name, name) ) {
00352     
00353     free(p->value);
00354     p->value= xstrdup(value);
00355     destroy_entry(h);
00356     return;
00357     
00358       }
00359       
00360     }
00361     
00362     n->next= h;
00363     
00364   } else {
00365     
00366     res->headers= h;
00367     
00368   }
00369 
00370 }
00371 
00372 
00379 void set_status(HttpResponse res, int code, char *msg) {
00380   
00381   res->status= code;
00382   free(res->status_msg);
00383   res->status_msg= xstrdup(msg);
00384   
00385 }
00386 
00387 
00393 void set_content_type(HttpResponse res, char *mime) {
00394 
00395   set_header(res, "Content-Type", mime);
00396 
00397 }
00398 
00399 
00406 char *get_header(HttpRequest req, const char *name) {
00407 
00408   HttpHeader p;
00409 
00410   for ( p= req->headers; p; p= p->next) {
00411     
00412     if ( !strcasecmp(p->name, name) ) {
00413       
00414     return xstrdup(p->value);
00415 
00416     }
00417     
00418   }
00419 
00420   return NULL;
00421 
00422 }
00423 
00424 
00431 char *get_parameter(HttpRequest req, const char *name) {
00432 
00433   HttpParameter p;
00434 
00435   for ( p= req->params; p; p= p->next) {
00436     
00437     if ( !strcasecmp(p->name, name) ) {
00438       
00439     return xstrdup(p->value);
00440 
00441     }
00442     
00443   }
00444 
00445   return NULL;
00446 
00447 }
00448 
00449 
00457 char *get_headers(HttpResponse res) {
00458 
00459   HttpHeader p;
00460   char buf[RES_STRLEN];
00461   char *b= buf;
00462 
00463   for ( p= res->headers; p; p= p->next) {
00464     
00465     b+= sprintf(b, "%s: %s\r\n", p->name, p->value);
00466     
00467   }
00468   
00469   return buf[0]?xstrdup(buf):NULL;
00470 
00471 }
00472 
00473 
00481 char *get_status_string(int status) {
00482 
00483   switch (status) {
00484   case SC_OK:
00485       return xstrdup("OK");
00486   case SC_ACCEPTED:
00487       return xstrdup("Accepted");
00488   case SC_BAD_GATEWAY:
00489       return xstrdup("Bad Gateway");
00490   case SC_BAD_REQUEST:
00491       return xstrdup("Bad Request");
00492   case SC_CONFLICT:
00493       return xstrdup("Conflict");
00494   case SC_CONTINUE:
00495       return xstrdup("Continue");
00496   case SC_CREATED:
00497       return xstrdup("Created");
00498   case SC_EXPECTATION_FAILED:
00499       return xstrdup("Expectation Failed");
00500   case SC_FORBIDDEN:
00501       return xstrdup("Forbidden");
00502   case SC_GATEWAY_TIMEOUT:
00503       return xstrdup("Gateway Timeout");
00504   case SC_GONE:
00505       return xstrdup("Gone");
00506   case SC_VERSION_NOT_SUPPORTED:
00507       return xstrdup("HTTP Version Not Supported");
00508   case SC_INTERNAL_SERVER_ERROR:
00509       return xstrdup("Internal Server Error");
00510   case SC_LENGTH_REQUIRED:
00511       return xstrdup("Length Required");
00512   case SC_METHOD_NOT_ALLOWED:
00513       return xstrdup("Method Not Allowed");
00514   case SC_MOVED_PERMANENTLY:
00515       return xstrdup("Moved Permanently");
00516   case SC_MOVED_TEMPORARILY:
00517       return xstrdup("Moved Temporarily");
00518   case SC_MULTIPLE_CHOICES:
00519       return xstrdup("Multiple Choices");
00520   case SC_NO_CONTENT:
00521       return xstrdup("No Content");
00522   case SC_NON_AUTHORITATIVE:
00523       return xstrdup("Non-Authoritative Information");
00524   case SC_NOT_ACCEPTABLE:
00525       return xstrdup("Not Acceptable");
00526   case SC_NOT_FOUND:
00527       return xstrdup("Not Found");
00528   case SC_NOT_IMPLEMENTED:
00529       return xstrdup("Not Implemented");
00530   case SC_NOT_MODIFIED:
00531       return xstrdup("Not Modified");
00532   case SC_PARTIAL_CONTENT:
00533       return xstrdup("Partial Content");
00534   case SC_PAYMENT_REQUIRED:
00535       return xstrdup("Payment Required");
00536   case SC_PRECONDITION_FAILED:
00537       return xstrdup("Precondition Failed");
00538   case SC_PROXY_AUTHENTICATION_REQUIRED:
00539       return xstrdup("Proxy Authentication Required");
00540   case SC_REQUEST_ENTITY_TOO_LARGE:
00541       return xstrdup("Request Entity Too Large");
00542   case SC_REQUEST_TIMEOUT:
00543       return xstrdup("Request Timeout");
00544   case SC_REQUEST_URI_TOO_LARGE:
00545       return xstrdup("Request URI Too Large");
00546   case SC_RANGE_NOT_SATISFIABLE:
00547       return xstrdup("Requested Range Not Satisfiable");
00548   case SC_RESET_CONTENT:
00549       return xstrdup("Reset Content");
00550   case SC_SEE_OTHER:
00551       return xstrdup("See Other");
00552   case SC_SERVICE_UNAVAILABLE:
00553       return xstrdup("Service Unavailable");
00554   case SC_SWITCHING_PROTOCOLS:
00555       return xstrdup("Switching Protocols");
00556   case SC_UNAUTHORIZED:
00557       return xstrdup("Unauthorized");
00558   case SC_UNSUPPORTED_MEDIA_TYPE:
00559       return xstrdup("Unsupported Media Type");
00560   case SC_USE_PROXY:
00561       return xstrdup("Use Proxy");
00562   default: {
00563      char buf[STRLEN];
00564      snprintf(buf, STRLEN, "HTTP Response Status %d", status);
00565      return xstrdup(buf);
00566     } 
00567   }
00568 
00569 }
00570 
00571 
00572 /* ----------------------------------------------------------------- Private */
00573 
00574 
00579 static void do_service(RequestWrapper w) {
00580 
00581   volatile HttpResponse res= create_HttpResponse(w);
00582   volatile HttpRequest req= create_HttpRequest(w);
00583 
00584   if ( res && req ) {
00585 
00586     if ( is_authenticated(req, res) ) {
00587       
00588       if ( !strcmp(req->method, METHOD_GET) ) {
00589 
00590     Impl.doGet(req, res);
00591     
00592       }
00593       else if ( !strcmp(req->method, METHOD_POST) ) {
00594 
00595     Impl.doPost(req, res);
00596     
00597       }
00598       else {
00599     
00600     send_error(res, SC_NOT_IMPLEMENTED, "Method not implemented");
00601     
00602       }
00603 
00604     }
00605 
00606     if ( Run.httpdssl ) {
00607 
00608       send_response(res);
00609       
00610     } else {
00611 
00612       if ( check_socket(w->socket) ) {
00613     
00614     send_response(res);
00615       }
00616 
00617     }
00618     
00619   }
00620 
00621   done(req, res);
00622   
00623 }
00624 
00625 
00629 static char *get_date() {
00630 
00631   char date[STRLEN];
00632   time_t now;
00633   
00634   time(&now);
00635   
00636   if ( !strftime(date, STRLEN, DATEFMT, gmtime(&now)) ) {
00637     
00638       memset(date, 0, STRLEN);
00639 
00640   }
00641   
00642   return xstrdup(date);
00643   
00644 }
00645 
00646 
00650 static char *get_server() {
00651 
00652   char server[STRLEN];
00653   snprintf(server, STRLEN, "%s %s", SERVER_NAME, SERVER_VERSION);
00654   
00655   return xstrdup(server);
00656   
00657 }
00658 
00659 
00664 static void send_response(HttpResponse res) {
00665 
00666   if ( !res->is_committed ) {
00667     char *date= get_date();
00668     char *server= get_server();
00669     char *headers= get_headers(res);
00670     int  len= res->bufused?strlen(res->outputbuffer):0;
00671 
00672     if ( Run.httpdssl ) {
00673 
00674       printf_ssl_socket(res->ssl, "%s %d %s\r\n", res->protocol, res->status, 
00675             res->status_msg);
00676       printf_ssl_socket(res->ssl, "Date: %s\r\n", date);
00677       printf_ssl_socket(res->ssl, "Server: %s\r\n", server);
00678       printf_ssl_socket(res->ssl, "Content-length: %d\r\n", len);
00679       printf_ssl_socket(res->ssl, "Connection: close\r\n");
00680       if ( headers ) printf_ssl_socket(res->ssl, "%s", headers);
00681       printf_ssl_socket(res->ssl, "\r\n\r\n");
00682       
00683       if ( res->bufused ) send_ssl_socket(res->ssl, res->outputbuffer, len);
00684 
00685     } else {
00686  
00687       FILE *out= res->outputstream;
00688     
00689       fprintf(out, "%s %d %s\r\n", res->protocol, res->status, 
00690           res->status_msg);
00691       fprintf(out, "Date: %s\r\n", date);
00692       fprintf(out, "Server: %s\r\n", server);
00693       fprintf(out, "Content-length: %d\r\n", len);
00694       fprintf(out, "Connection: close\r\n");
00695       if ( headers ) fprintf(out, "%s", headers);
00696       fprintf(out, "\r\n\r\n");
00697       
00698       if ( res->bufused ) fprintf(out, "%s", res->outputbuffer);
00699       
00700     }
00701     
00702     free(headers);
00703     free(date);
00704     free(server);
00705     
00706   }
00707 
00708 }
00709 
00710 
00711 /* --------------------------------------------------------------- Factories */
00712 
00713 
00717 static HttpRequest create_HttpRequest(RequestWrapper W) {
00718 
00719   char line[REQ_STRLEN];
00720   char method[STRLEN];
00721   char url[REQ_STRLEN];
00722   char protocol[STRLEN]; 
00723   HttpRequest req;
00724   FILE *in= NULL;
00725 
00726   if ( Run.httpdssl ) {
00727 
00728     if ( gets_ssl_socket(W->ssl, line, sizeof(line)) == NULL ) {
00729       
00730       internal_error_ssl(W->ssl, SC_BAD_REQUEST, "No request found");
00731       return NULL;
00732       
00733     }
00734 
00735     if ( sscanf(line, "%s %s HTTP/%3[1.0]", method, url, protocol) != 3 ) {
00736       
00737       internal_error_ssl(W->ssl, SC_BAD_REQUEST, "Cannot parse request");
00738       return NULL;
00739       
00740     }
00741 
00742   } else {
00743 
00744     in= fdopen(dup(W->socket), "r");
00745       
00746     if ( in == NULL ) {
00747       
00748       internal_error(W->socket, SC_INTERNAL_SERVER_ERROR,
00749              "Cannot create inputstream");
00750       return NULL;
00751       
00752     }
00753     
00754     if ( fgets(line, sizeof(line), in) == NULL ) {
00755       
00756       internal_error(W->socket, SC_BAD_REQUEST, "No request found");
00757       fclose(in);
00758       return NULL;
00759       
00760     }
00761     
00762     if ( sscanf(line, "%s %s HTTP/%3[1.0]", method, url, protocol) != 3 ) {
00763       
00764       internal_error(W->socket, SC_BAD_REQUEST, "Cannot parse request");
00765       fclose(in);
00766       return NULL;
00767       
00768     }
00769   }
00770 
00771   req= NEW(req);
00772   unescape_url(url);
00773   chomp(protocol);
00774   req->method= xstrdup(method);
00775   req->url= xstrdup(url);
00776   req->protocol= xstrdup(protocol); 
00777   req->ssl= W->ssl;
00778 
00779   if (! Run.httpdssl ) {
00780  
00781    req->inputstream= in;
00782 
00783   } else {
00784 
00785    req->inputstream= NULL;
00786 
00787   }
00788 
00789   req->inetaddr= W->inetaddr;
00790 
00791   create_headers(req);
00792 
00793   if ( !create_parameters(req) ) {
00794     
00795     if ( Run.httpdssl ) {
00796 
00797       internal_error_ssl(W->ssl, SC_BAD_REQUEST,
00798              "Cannot parse Request parameters");
00799 
00800     } else {
00801 
00802       internal_error(W->socket, SC_BAD_REQUEST,
00803              "Cannot parse Request parameters");
00804       fclose(in);
00805 
00806     }
00807 
00808     return NULL;
00809     
00810   }
00811     
00812   return req;
00813   
00814 }
00815 
00816 
00821 static HttpResponse create_HttpResponse(RequestWrapper W) {
00822   
00823   HttpResponse res;
00824   FILE *out= NULL;
00825 
00826   if ( ! Run.httpdssl ) {
00827 
00828     out = fdopen(dup(W->socket), "w");
00829 
00830     if ( out == NULL ) {
00831     
00832       internal_error(W->socket, SC_INTERNAL_SERVER_ERROR,
00833              "Cannot create outputstream");
00834       
00835       return NULL;
00836     }
00837 
00838   }
00839   
00840   res= NEW(res);
00841   res->protocol= xstrdup(SERVER_PROTOCOL);
00842   res->status= 200;
00843   res->status_msg= get_status_string(SC_OK);
00844   res->outputstream= out;
00845   res->outputbuffer= NULL;
00846   res->bufsize= 0;
00847   res->bufused= 0;
00848   res->is_committed= FALSE;
00849   res->ssl= W->ssl;
00850   
00851   return res;
00852   
00853 }
00854 
00855 
00859 static void create_headers(HttpRequest req) {
00860 
00861   char line[REQ_STRLEN];
00862   char *value;
00863   HttpHeader p;
00864   HttpHeader header;
00865 
00866   while ( 1 ) {
00867 
00868     if ( Run.httpdssl ) {
00869 
00870       if (NULL == gets_ssl_socket(req->ssl, line, sizeof(line))) {
00871 
00872     break;
00873 
00874       }
00875 
00876     } else {
00877 
00878       if (NULL == fgets(line, sizeof(line), req->inputstream)) {
00879 
00880     break;
00881 
00882       }
00883 
00884     }
00885 
00886     if ( !strcmp(line, "\r\n") || !strcmp(line, "\n") )
00887     break;
00888     
00889     if( NULL != (value= strchr(line, ':')) ) {
00890       
00891       header= NEW(header);
00892       *value++= '\0';
00893       trim(line);
00894       trim(value);
00895       chomp(value);
00896       header->name= xstrdup(line);
00897       header->value= xstrdup(value);
00898       
00899       if ( req->headers ) {
00900     
00901     for ( p= req->headers; p->next; p= p->next)
00902         /* Empty */;
00903     p->next= header;
00904     
00905       } else {
00906     
00907     req->headers= header;
00908     
00909       }
00910       
00911     }
00912     
00913   }
00914   
00915 }
00916 
00917 
00922 static int create_parameters(HttpRequest req) {
00923 
00924   char *query_string= NULL;
00925   int alloc= FALSE;
00926 
00927   if ( !strcmp(req->method, METHOD_POST) ) {
00928     
00929     int len; char *l= get_header(req, "Content-Length");
00930     
00931     if ( l && (len= atoi(l)) ) {
00932       
00933       query_string= xmalloc(sizeof(char) * (len + 1));
00934       
00935       if ( fgets(query_string, (sizeof(char)*(len+1)),
00936          req->inputstream) == NULL ) {
00937     
00938     free(query_string);
00939     return FALSE;
00940     
00941       }
00942       
00943       alloc= TRUE;
00944       
00945     }
00946     
00947   } else if ( !strcmp(req->method, METHOD_GET) ) {
00948     
00949     char *p;
00950     
00951     if( NULL != (p= strchr(req->url, '?')) ) {
00952       
00953       *p++= '\0';
00954       query_string= p;
00955       
00956     }
00957     
00958   }
00959   
00960   if ( query_string ) {
00961     
00962     char *p;
00963     
00964     if( NULL != (p= strchr(query_string, '/')) ) {
00965       
00966       *p++= '\0';
00967       req->pathinfo= p;
00968       
00969     }
00970     
00971     req->params= parse_parameters(query_string);
00972     
00973   }
00974 
00975   if ( alloc ) free(query_string);
00976   
00977   return TRUE;
00978   
00979 }
00980 
00981 
00982 
00983 /* ----------------------------------------------------------------- Cleanup */
00984 
00985 
00989 static void reset_response(HttpResponse res) {
00990 
00991   if ( res->headers ) destroy_entry(res->headers);
00992   memset(res->outputbuffer, 0, res->bufsize);
00993   res->headers= NULL; /* Release Pragma */
00994   
00995 }
00996 
00997 
01001 static void done(HttpRequest req, HttpResponse res) {
01002 
01003   destroy_HttpRequest(req);
01004   destroy_HttpResponse(res);
01005 
01006 }
01007 
01008 
01012 static void destroy_HttpRequest(HttpRequest req) {
01013 
01014   if ( req ) {
01015     
01016     if ( req->inputstream ) fclose(req->inputstream);
01017     free(req->method);
01018     free(req->url); /* req->pathinfo is freed with url */
01019     free(req->protocol);
01020     if ( req->headers ) destroy_entry(req->headers);
01021     if ( req->params ) destroy_entry(req->params);
01022     free(req);
01023     
01024   }
01025   
01026 }
01027 
01028 
01032 static void destroy_HttpResponse(HttpResponse res) {
01033 
01034   if ( res ) {
01035     
01036     if ( res->outputstream ) fclose(res->outputstream);
01037     free(res->protocol);
01038     free(res->status_msg);
01039     free(res->outputbuffer);
01040     if ( res->headers) destroy_entry(res->headers);
01041     free(res);
01042     
01043   }
01044   
01045 }
01046 
01047 
01052 static void destroy_entry(void *p) {
01053   
01054   struct entry *h= p; 
01055   
01056   if ( h->next ) {
01057     
01058     destroy_entry(h->next);
01059     
01060   }
01061 
01062   free(h->name);
01063   free(h->value);
01064   free(h);
01065  
01066 }
01067 
01068 
01069 /* ----------------------------------------------------- Checkers/Validators */
01070 
01071 
01075 static int is_authenticated(HttpRequest req, HttpResponse res) {
01076 
01077   if ( Run.Auth.defined ) {
01078 
01079     if ( ! basic_authenticate(req) ) {
01080       
01081       send_error(res, SC_UNAUTHORIZED,
01082          "You are <b>not</b> authorized to access <i>monit</i>. "
01083          "Either you supplied the wrong credentials (e.g. bad "
01084          "password), or your browser doesn't understand how to supply "
01085          "the credentials required");
01086       set_header(res, "WWW-Authenticate", "Basic realm=\"monit\"");
01087       
01088       return FALSE;
01089       
01090     }
01091 
01092   }
01093 
01094   return TRUE;
01095 
01096 }
01097 
01098 
01103 static int basic_authenticate(HttpRequest req) {
01104 
01105   int rv= FALSE;
01106   char *credentials= get_header(req, "Authorization");
01107 
01108   if ( credentials ) {
01109 
01110     unsigned char *cr= xcalloc(sizeof(unsigned char), strlen(credentials)+1);
01111 
01112     if ( decode_base64(cr, strchr(credentials, ' ')) ) {
01113 
01114       char buf[STRLEN];
01115 
01116       snprintf(buf, STRLEN, "%s:%s", Run.Auth.uname, Run.Auth.passwd);
01117       
01118       if ( !strncmp(cr, buf, strlen(buf)) ) {
01119       
01120       rv= TRUE;
01121       
01122       }
01123     
01124     }
01125     
01126     free(cr);
01127     free(credentials);
01128 
01129   }
01130   
01131   return rv;
01132   
01133 }
01134 
01135 
01136 /* --------------------------------------------------------------- Utilities */
01137 
01138 
01144 static void internal_error(int client, int status, char *msg) {
01145 
01146   char response[RES_STRLEN];
01147   char *server= get_server();
01148   char *date= get_date();
01149   char *status_msg= get_status_string(status);
01150 
01151   snprintf(response, RES_STRLEN,
01152        "%s %d %s\r\n"
01153        "Date: %s\r\n"
01154        "Server: %s\r\n"
01155        "Content-Type: text/html\r\n"
01156        "Connection: close\r\n"
01157        "\r\n"
01158        "<html><head><title>%s</title></head>"
01159        "<body bgcolor=#FFFFFF><h2>%s</h2>%s<p>"
01160        "<hr><a href='%s'><font size=-1>%s</font></a>"
01161        "</body></html>\r\n",
01162        SERVER_PROTOCOL, status, status_msg, date, server,
01163        status_msg, status_msg, msg, SERVER_URL, server);
01164   sock_send(client, response, strlen(response), 0);
01165   free(server);
01166   free(date);
01167   free(status_msg);
01168   
01169 }
01170 
01171 static void internal_error_ssl(ssl_connection *ssl, int status, char *msg) {
01172 
01173   char response[RES_STRLEN];
01174   char *server= get_server();
01175   char *date= get_date();
01176   char *status_msg= get_status_string(status);
01177 
01178   snprintf(response, RES_STRLEN,
01179        "%s %d %s\r\n"
01180        "Date: %s\r\n"
01181        "Server: %s\r\n"
01182        "Content-Type: text/html\r\n"
01183        "Connection: close\r\n"
01184        "\r\n"
01185        "<html><head><title>%s</title></head>"
01186        "<body bgcolor=#FFFFFF><h2>%s</h2>%s<p>"
01187        "<hr><a href='%s'><font size=-1>%s</font></a>"
01188        "</body></html>\r\n",
01189        SERVER_PROTOCOL, status, status_msg, date, server,
01190        status_msg, status_msg, msg, SERVER_URL, server);
01191 
01192   send_ssl_socket(ssl, response, strlen(response));
01193   free(server);
01194   free(date);
01195   free(status_msg);
01196   
01197 }
01198 
01199 
01204 static HttpParameter parse_parameters(char *query_string) {
01205 
01206   HttpParameter head= NULL;
01207   int controller= 1000;
01208   
01209   while ( query_string[0] && controller-- ) {
01210     
01211     HttpParameter p= NEW(p);
01212     p->value= makeword(query_string,'&');
01213     p->name= makeword(p->value,'=');
01214     plustospace(p->value);
01215     unescape_url(p->value);
01216     plustospace(p->name);
01217     unescape_url(p->name);
01218     p->next= head;
01219     head= p;
01220     
01221   }
01222 
01223   return head;
01224   
01225 }
01226 
01227 
01234 static int is_available(int s) {
01235 
01236   fd_set rset;
01237   struct timeval tv;
01238 
01239   if(s < 0)
01240       return FALSE;
01241   
01242   FD_ZERO(&rset);
01243   FD_SET(s, &rset);
01244   tv.tv_sec= REQUEST_TIMEOUT;
01245   tv.tv_usec= 0;
01246 
01247   return (select(s+1, &rset, NULL, NULL, &tv)>0);
01248 
01249 }
01250