/*- * Copyright (c) 1999, 2000, 2001, 2002, 2003 Lev Walkin . * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id: param.c,v 1.4 2005/05/25 21:55:10 vlm Exp $ */ #include #include #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include int _sf_cgi_parse_multipart(char *data, size_t len); static svect *_sf_attr = NULL; static svect *_sf_vals = NULL; static svect *_sf_unmv = NULL; /* Unmodified value */ static svect *_sf_type = NULL; /* Content-type */ #define __VECT_INIT(var) do { \ if(var) { \ sclear(var); \ } else { \ var = sinit(); \ if((var) == NULL) { \ /* ENOMEM? */ \ return -1; \ } \ } \ } while(0) int parse_form(void); /* This declaration is extern, but not exposed */ int parse_form() { static int parsed = 0; int n; char *af, *as; svect *sl = NULL; char *s; if(parsed) return 0; __VECT_INIT(_sf_attr); __VECT_INIT(_sf_vals); __VECT_INIT(_sf_unmv); __VECT_INIT(_sf_type); if(!(s=getenv("REQUEST_METHOD")) || (strcmp(s, "GET") && strcmp(s, "HEAD") && strcmp(s, "POST"))) { /* Invalid input */ errno = EINVAL; return -1; } if(strcmp(s, "POST")) { if(!(s=getenv("QUERY_STRING"))) { errno = EINVAL; return -1; } sl = split(s, "&", 0); if(sl == NULL) { /* ENOMEM? */ return -1; } } else { char *buf; ssize_t buflen, bl, tmp; int known_content_length; if(!(s=getenv("CONTENT_LENGTH")) || (buflen=atoi(s)) < 0) { buflen = 4091; /* Probably, one page */ known_content_length = 0; } else { known_content_length = 1; } buf=(char *)sf_malloc(buflen+1); if(buf == NULL) /* ENOMEM? */ return -1; /* Read into previoulsy allocated buffer */ for(bl = 0; bl < buflen; ) { tmp = read(0, buf+bl, buflen - bl); if(tmp == -1) { if(errno == EINTR) continue; free(buf); /* read() will return value */ return -1; } if(tmp == 0) { if(known_content_length) return -1; break; } bl+=tmp; } /* Terminating with zero */ buf[buflen=bl] = '\0'; /* Parse differently, if it is multipart form. */ if((s=getenv("CONTENT_TYPE")) && !strncasecmp(s, "multipart/form-data", sizeof("multipart/form-data")-1)) { tmp = _sf_cgi_parse_multipart(buf, buflen); free(buf); /* Invalid data supplied */ errno = EINVAL; return tmp; } sl = split(buf, "&", 0); free(buf); } if(sl->count == 0) { sfree(sl); return 0; } for(n = 0; n < sl->count; n++) { af = sl->list[n]; if((as=strchr(af, '='))) *as++ = '\0'; if(sadd(_sf_attr, url_decode(af)) == -1 || sadd(_sf_unmv, as?as:"") == -1 /* Unmodified value */ || sadd(_sf_vals, url_decode(as)) == -1 /* Decoded value */ || sadd(_sf_type, "text/unknown") == -1 ) { sfree(sl); /* ENOMEM? */ return -1; } } sfree(sl); parsed = 1; return 0; } char * param(char *field) { if(_sf_attr == NULL) { if(parse_form() == -1) return NULL; } return scget2(_sf_attr, field, _sf_vals); } svect * param2(char *field, int flag) { static svect *sl = NULL; svect *vals; int n; if(_sf_attr == NULL) { if(parse_form() == -1) return NULL; } if(sl == NULL) { sl = sinit(); if(sl == NULL) return NULL; } else { sl->count = 0; sl->maxlen = 0; sl->list[0] = NULL; sl->lens[0] = 0; } if(field == NULL) return sl; switch(flag) { case 0: vals = _sf_vals; break; case 1: vals = _sf_unmv; break; case 2: vals = _sf_type; break; default: vals = _sf_vals; } for(n = 0; n < _sf_attr->count; n++) if(ecq(_sf_attr->list[n], field)) sadd2(sl, vals->list[n], vals->lens[n]); return sl; } /* * Returns an array of passed CGI attributes. */ svect * params() { if(_sf_attr == NULL) { if(parse_form() == -1) return NULL; } return _sf_attr; } int _sf_cgi_parse_multipart(char *data, size_t len) { char *bnd; int bndlen; char *dp = data; char *sd = NULL; /* start data */ char *fname = NULL; char *name = NULL; char *ct = NULL; char *tmp; svect *sl1, *sl2; int i, z; if(dp == NULL) return 0; if((bnd=getenv("CONTENT_TYPE")) == NULL) return 0; if((bnd=strstr(bnd, "boundary=")) == NULL) return 0; bnd+=sizeof("boundary")-2; bnd=sf_strdup(bnd); if(bnd == NULL) return 0; *bnd = bnd[1] = '-'; bndlen = strlen(bnd); sl1 = sinit(); if(sl1 == NULL) return -1; sl2 = sinit(); if(sl2 == NULL) return -1; while(dp-data < len) { if(strncmp(dp, bnd, bndlen)) { dp++; continue; } *(dp-1) = *(dp-2) = '\0'; if(sd) { if( sadd(_sf_attr, name?name:"UNKNOWN") == -1 || sadd(_sf_type, ct?ct:"") == -1 ) { sfree(sl1); sfree(sl2); return -1; } if(fname) { if( sadd(_sf_vals, fname) == -1 || sadd2(_sf_unmv, sd, dp-sd-2) == -1 ) { sfree(sl1); sfree(sl2); return -1; } } else { if( sadd2(_sf_vals, sd, dp-sd-2) == -1 || sadd2(_sf_unmv, sd, dp-sd-2) == -1 ) { sfree(sl1); sfree(sl2); return -1; } } fname=name=sd=ct = NULL; } dp+=bndlen; if(strncmp(dp, "--\r\n", 4) == 0) break; dp+=2; /* Part started */ tmp = strstr(dp, "\r\n\r\n"); tmp += 2; *tmp = '\0'; sd = tmp + 2; for(tmp = dp; *tmp; tmp++) { if(*tmp == ';') *tmp = ' '; } sclear(sl1); splitf(sl1, dp, "\r\n", 0); if(sl1->count == 0) continue; for(i = 0; icount; i++) { if(!strncasecmp(sl1->list[i], "Content-Disposition:", sizeof("Content-Disposition:")-1)) { sclear(sl2); splitquotable(sl2, sl1->list[i]); for(z = 0; z < sl2->count; z++) { if(!strncasecmp(sl2->list[z], "name=", 5)) name=sl2->list[z]+5; else if(!strncasecmp(sl2->list[z], "filename=", 9)) fname=sl2->list[z]+9; } } else if(!strncasecmp(sl1->list[i], "Content-Type:", sizeof("Content-Type:")-1)) { ct=sl1->list[i] + sizeof("Content-Type:") - 1; while(*ct == ' ') ct++; } } } sfree(sl1); sfree(sl2); return 1; }