grst_http.c

Go to the documentation of this file.
00001 /*
00002    Copyright (c) 2002-3, Andrew McNab, University of Manchester
00003    All rights reserved.
00004 
00005    Redistribution and use in source and binary forms, with or
00006    without modification, are permitted provided that the following
00007    conditions are met:
00008 
00009      o Redistributions of source code must retain the above
00010        copyright notice, this list of conditions and the following
00011        disclaimer. 
00012      o Redistributions in binary form must reproduce the above
00013        copyright notice, this list of conditions and the following
00014        disclaimer in the documentation and/or other materials
00015        provided with the distribution. 
00016 
00017    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
00018    CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
00019    INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00020    MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00021    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
00022    BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00023    EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
00024    TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00025    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
00026    ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00027    OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00028    OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00029    POSSIBILITY OF SUCH DAMAGE.
00030 */
00031 
00032 #ifndef VERSION
00033 #define VERSION "x.x.x"
00034 #endif
00035 
00036 #ifndef _GNU_SOURCE
00037 #define _GNU_SOURCE
00038 #endif
00039 
00040 #include <stdio.h>
00041 
00042 #include <time.h>
00043 #include <stdlib.h>
00044 #include <stdarg.h>
00045 #include <string.h>
00046 #include <strings.h>
00047 #include <unistd.h>
00048 #include <dirent.h>
00049 #include <errno.h>
00050 #include <sys/types.h>
00051 #include <sys/stat.h>
00052 #include <fcntl.h>
00053 #include <ctype.h>
00054 
00055 #include "gridsite.h"
00056 
00057 void GRSThttpBodyInit(GRSThttpBody *thisbody)
00058 {
00059   thisbody->size = 0; /* simple, but we don't expose internals to callers */
00060 }
00061 
00062 void GRSThttpPrintf(GRSThttpBody *thisbody, char *fmt, ...)
00063 /* append printf() style format and arguments to *thisbody. */
00064 
00065 {
00066   char    p[16384];
00067   size_t   size;
00068   va_list  args;
00069 
00070   va_start(args, fmt);
00071   size = vsprintf(p, fmt, args);  
00072   va_end(args);
00073 
00074   if (size >  0)
00075     {
00076       if (thisbody->size == 0) /* need to initialise */
00077         {
00078           thisbody->first = (GRSThttpCharsList *)malloc(sizeof(GRSThttpCharsList));
00079           thisbody->first->text = p;
00080           thisbody->first->next = NULL;
00081       
00082           thisbody->last = thisbody->first;          
00083           thisbody->size = size;
00084         }
00085       else
00086         {
00087           thisbody->last->next = (GRSThttpCharsList *)
00088                                                malloc(sizeof(GRSThttpCharsList));
00089           ((GRSThttpCharsList *) thisbody->last->next)->text = p;
00090           ((GRSThttpCharsList *) thisbody->last->next)->next = NULL;
00091       
00092           thisbody->last = thisbody->last->next;          
00093           thisbody->size = thisbody->size + size;
00094         }
00095     }
00096 }
00097 
00098 int GRSThttpCopy(GRSThttpBody *thisbody, char *file)
00099 /* 
00100    copy a whole file, named file[], into the body output buffer, returning
00101    1 if file was found and copied ok, or 0 otherwise.
00102 */
00103 {
00104   int         fd, len;
00105   char        *p;
00106   struct stat statbuf;
00107 
00108   fd = open(file, O_RDONLY);
00109 
00110   if (fd == -1) return 0;
00111 
00112   if (fstat(fd, &statbuf) != 0)
00113     {
00114       close(fd);
00115       return 0;
00116     }
00117 
00118   p = malloc(statbuf.st_size + 1);
00119 
00120   if (p == NULL)
00121     {
00122       close(fd);
00123       return 0;
00124     }
00125 
00126   len = read(fd, p, statbuf.st_size);
00127   p[len] = '\0';
00128 
00129   close(fd);
00130    
00131   if (thisbody->size == 0) /* need to initialise */
00132     {
00133       thisbody->first = (GRSThttpCharsList *) malloc(sizeof(GRSThttpCharsList));
00134       thisbody->first->text = p;
00135       thisbody->first->next = NULL;
00136       
00137       thisbody->last = thisbody->first;
00138       thisbody->size = len;
00139     }
00140   else
00141     { 
00142       thisbody->last->next=(GRSThttpCharsList *)malloc(sizeof(GRSThttpCharsList));
00143       ((GRSThttpCharsList *) thisbody->last->next)->text = p;
00144       ((GRSThttpCharsList *) thisbody->last->next)->next = NULL;
00145       
00146       thisbody->last = thisbody->last->next;
00147       thisbody->size = thisbody->size + len;
00148     }
00149 
00150   return 1;      
00151 }
00152 
00153 void GRSThttpWriteOut(GRSThttpBody *thisbody)
00154 /* output Content-Length header, blank line then whole of the body to
00155    standard output */
00156 {
00157   GRSThttpCharsList *p;
00158   
00159   printf("Content-Length: %d\n\n", (int)thisbody->size);
00160 
00161   p = thisbody->first;
00162   
00163   while (p != NULL)
00164     {
00165       fputs(p->text, stdout);
00166     
00167       p = p->next;      
00168     }
00169 }
00170 
00171 int GRSThttpPrintHeaderFooter(GRSThttpBody *bp, char *file, char *headfootname)
00172 /* 
00173     try to print Header or Footer appropriate for absolute path file[],
00174     returning 1 rather than 0 if found.
00175 */
00176 {
00177   int          found = 0;
00178   char        *pathfile, *p;
00179   struct stat  statbuf;
00180 
00181   pathfile = malloc(strlen(file) + strlen(headfootname) + 2);
00182   strcpy(pathfile, file);
00183 
00184   if ((pathfile[strlen(pathfile) - 1] != '/') &&
00185       (stat(pathfile, &statbuf) == 0) && 
00186        S_ISDIR(statbuf.st_mode)) strcat(pathfile, "/");
00187   
00188   for (;;)
00189      {
00190        p = rindex(pathfile, '/');
00191        if (p == NULL) break;
00192        p[1] = '\0';
00193        strcat(p, headfootname);
00194 
00195        if (stat(pathfile, &statbuf) == 0)
00196          {
00197            found = GRSThttpCopy(bp, pathfile);
00198            break;
00199          }
00200 
00201        p[0] = '\0';
00202      }
00203 
00204   free(pathfile);
00205   return found;
00206 }
00207 
00208 int GRSThttpPrintHeader(GRSThttpBody *bp, char *file)
00209 {
00210   char *headname;
00211   
00212   headname = getenv("REDIRECT_GRST_HEAD_FILE");
00213   if (headname == NULL) headname = getenv("GRST_HEAD_FILE");
00214   if (headname == NULL) headname = GRST_HEADFILE;
00215 
00216   if (headname[0] == '/') /* absolute location */
00217     {
00218       return GRSThttpCopy(bp, headname);
00219     }
00220     
00221   return GRSThttpPrintHeaderFooter(bp, file, headname);
00222 }
00223 
00224 int GRSThttpPrintFooter(GRSThttpBody *bp, char *file)
00225 {
00226   char *footname;
00227   
00228   footname = getenv("REDIRECT_GRST_FOOT_FILE");
00229   if (footname == NULL) footname = getenv("GRST_FOOT_FILE");
00230   if (footname == NULL) footname = GRST_FOOTFILE;
00231 
00232   if (footname[0] == '/') /* absolute location */
00233     {
00234       return GRSThttpCopy(bp, footname);
00235     }
00236     
00237   return GRSThttpPrintHeaderFooter(bp, file, footname);
00238 }
00239 
00240 char *GRSThttpGetCGI(char *name)
00241 /* 
00242    Return a malloc()ed copy of CGI form parameter identified by name[],
00243    either received by QUERY_STRING (via GET) or on stdin (via POST).
00244    Caller must free() the returned string itself. If name[] is not found,
00245    an empty NUL-terminated malloc()ed string is returned. name[] has any
00246    URL-encoding reversed.
00247 */
00248 {
00249   char   *p, *namepattern, *valuestart, *returnvalue, *querystring;
00250   int     c, i, j, n, contentlength = 0;
00251   static char *cgiposted = NULL;
00252 
00253   if (cgiposted == NULL) /* have to initialise cgiposted */
00254     {
00255       p = getenv("CONTENT_LENGTH");
00256       if (p != NULL) sscanf(p, "%d", &contentlength);
00257 
00258       querystring = getenv("REDIRECT_QUERY_STRING");
00259       if (querystring == NULL) querystring = getenv("QUERY_STRING");
00260       
00261       if (querystring == NULL) cgiposted = malloc(contentlength + 3);
00262       else cgiposted = malloc(contentlength + strlen(querystring) + 4);
00263 
00264       cgiposted[0] = '&';
00265 
00266       for (i = 1; i <= contentlength; ++i)
00267          {
00268            c = getchar();
00269            if (c == EOF) break;
00270            cgiposted[i] = c;           
00271          }
00272 
00273       cgiposted[i]   = '&';
00274       cgiposted[i+1] = '\0';
00275 
00276       if (querystring != NULL)
00277         {
00278           strcat(cgiposted, querystring);
00279           strcat(cgiposted, "&");
00280         }
00281     }
00282     
00283   namepattern = malloc(strlen(name) + 3);
00284   sprintf(namepattern, "&%s=", name);
00285   
00286   p = strstr(cgiposted, namepattern);
00287   free(namepattern);
00288   if (p == NULL) return strdup("");
00289      
00290   valuestart = &p[strlen(name) + 2];
00291 
00292   for (n=0; valuestart[n] != '&'; ++n) ;
00293   
00294   returnvalue = malloc(n + 1);
00295   
00296   j=0;
00297   
00298   for (i=0; i < n; ++i) 
00299      {
00300        if ((i < n - 2) && (valuestart[i] == '%')) /* url encoded as %HH */
00301          {
00302            returnvalue[j] = 0;
00303            
00304            if (isdigit(valuestart[i+1])) 
00305                  returnvalue[j] += 16 * (valuestart[i+1] - '0');
00306            else if (isalpha(valuestart[i+1])) 
00307                  returnvalue[j] += 16 * (10 + tolower(valuestart[i+1]) - 'a');
00308                          
00309            if (isdigit(valuestart[i+2])) 
00310                  returnvalue[j] += valuestart[i+2] - '0';
00311            else if (isalpha(valuestart[i+2])) 
00312                  returnvalue[j] += 10 + tolower(valuestart[i+2]) - 'a';
00313 
00314            i = i + 2;
00315          }
00316        else if (valuestart[i] == '+') returnvalue[j] = ' ';
00317        else                           returnvalue[j] = valuestart[i];
00318        
00319        if (returnvalue[j] == '\r') continue; /* CR/LF -> LF */
00320        ++j;
00321      }
00322 
00323   returnvalue[j] = '\0';
00324 
00325   return returnvalue;
00326 }
00327 
00328 /*                   *
00329  * Utility functions *
00330  *                   */
00331 
00332 char *GRSThttpUrlDecode(char *in)
00333 {
00334   int   i, j, n;
00335   char *out;
00336                                                                                 
00337   n = strlen(in);
00338   out = malloc(n + 1);
00339                                                                                 
00340   j=0;
00341                                                                                 
00342   for (i=0; i < n; ++i)
00343      {
00344        if ((i < n - 2) && (in[i] == '%')) /* url encoded as %HH */
00345          {
00346            out[j] = 0;
00347                                                                                 
00348            if (isdigit(in[i+1]))
00349                  out[j] += 16 * (in[i+1] - '0');
00350            else if (isalpha(in[i+1]))
00351                  out[j] += 16 * (10 + tolower(in[i+1]) - 'a');
00352                                                                                 
00353            if (isdigit(in[i+2]))
00354                  out[j] += in[i+2] - '0';
00355            else if (isalpha(in[i+2]))
00356                  out[j] += 10 + tolower(in[i+2]) - 'a';
00357                                                                                 
00358            i = i + 2;
00359          }
00360        else if (in[i] == '+') out[j] = ' ';
00361        else                   out[j] = in[i];
00362                                                                                 
00363        ++j;
00364      }
00365                                                                                 
00366   out[j] = '\0';
00367                                                                                 
00368   return out;
00369 }
00370 
00371 char *GRSThttpUrlEncode(char *in)
00372 /* Return a pointer to a malloc'd string holding a URL-encoded (RFC 1738)
00373    version of *in. Only A-Z a-z 0-9 . _ - are passed through unmodified.
00374    (DN's processed by GRSThttpUrlEncode can be used as valid Unix filenames,
00375    assuming they do not exceed restrictions on filename length.) */
00376 {
00377   char *out, *p, *q;
00378   
00379   out = malloc(3*strlen(in) + 1);
00380   
00381   p = in;
00382   q = out;
00383   
00384   while (*p != '\0')
00385        {
00386          if (isalnum(*p) || (*p == '.') || (*p == '_') || (*p == '-'))
00387            {
00388              *q = *p;
00389              ++q;
00390            }
00391          else
00392            {
00393              sprintf(q, "%%%2X", *p);
00394              q = &q[3];
00395            }
00396 
00397          ++p;
00398        }
00399   
00400   *q = '\0';  
00401   return out;
00402 }
00403 
00404 char *GRSThttpUrlMildencode(char *in)
00405 /* Return a pointer to a malloc'd string holding a partially URL-encoded
00406    version of *in. "Partially" means that A-Z a-z 0-9 . = - _ @ and / 
00407    are passed through unmodified. (DN's processed by GRSThttpUrlMildencode()
00408    can be used as valid Unix paths+filenames if you are prepared to
00409    create or simulate the resulting /X=xyz directories.) */
00410 {
00411   char *out, *p, *q;
00412   
00413   out = malloc(3*strlen(in) + 1);
00414   
00415   p = in;
00416   q = out;
00417   
00418   while (*p != '\0')
00419        {
00420          if (isalnum(*p) || (*p == '.') || (*p == '=') || (*p == '-') 
00421                          || (*p == '/') || (*p == '@') || (*p == '_'))
00422            {
00423              *q = *p;
00424              ++q;
00425            }
00426          else if (*p == ' ')
00427            {
00428              *q = '+';
00429              ++q;
00430            }
00431          else
00432            {
00433              sprintf(q, "%%%2X", *p);
00434              q = &q[3];
00435            }
00436 
00437          ++p;
00438        }
00439   
00440   *q = '\0';  
00441   return out;
00442 }
00443 
00444 /// Return a one-time passcode string, for use with GridHTTP
00445 /**
00446  *  Returns
00447  *
00448  *  String is timestamp+SHA1_HASH(timestamp+":"+method+":"+URL)
00449  *  Timestamps and hashes are in lowercase hexadecimal. Timestamps are
00450  *  seconds since 00:00:00 on January 1, 1970 UTC.
00451  */
00452 
00453 /*
00454 char *GRSThttpMakeOneTimePasscode(time_t timestamp, char *method, char *url)
00455 {
00456   int    len, i;
00457   char  stringtohash[16384], hashedstring[EVP_MAX_MD_SIZE], *returnstring;
00458   const EVP_MD *m;
00459   EVP_MD_CTX ctx;
00460 
00461   m = EVP_sha1();
00462   if (m == NULL) return NULL;
00463 
00464   sprintf(stringtohash, "%08x:%s:%s", timestamp, method, url);
00465  
00466   EVP_DigestInit(&ctx, m);
00467   EVP_DigestUpdate(&ctx, stringtohash, strlen(stringtohash));
00468   EVP_DigestFinal(&ctx, hashedstring, &len);
00469 
00470   returnstring = malloc(9 + len * 2);
00471 
00472   sprintf(returnstring, "%08x", timestamp);
00473 
00474   for (i=0; 
00475 
00476   return returnstring;
00477 }
00478 */

Generated on Tue Jul 5 14:47:01 2011 for ROOT_528-00b_version by  doxygen 1.5.1