Annotation of parser3/src/types/pa_vform.C, revision 1.16

1.10      paf         1: /**
                      2:        Parser: form class.
                      3: 
1.3       paf         4:        Copyright(c) 2001 ArtLebedev Group(http://www.artlebedev.com)
1.10      paf         5: 
1.3       paf         6:        Author: Alexander Petrosyan <paf@design.ru>(http://design.ru/paf)
1.1       paf         7: 
1.16    ! paf         8:        $Id: pa_vform.C,v 1.15 2001/03/23 13:08:14 paf Exp $
1.1       paf         9: 
1.15      paf        10:        
                     11:        based on The CGI_C library, by Thomas Boutell.
1.3       paf        12: */
                     13: 
1.15      paf        14: #include "pa_config_includes.h"
1.3       paf        15: #include <ctype.h>
                     16: 
1.14      paf        17: #include "pa_sapi.h"
1.1       paf        18: #include "pa_vform.h"
                     19: #include "pa_vstring.h"
1.3       paf        20: #include "pa_globals.h"
                     21: #include "pa_request.h"
1.9       paf        22: #include "pa_vfile.h"
1.3       paf        23: 
                     24: // parse helper funcs
                     25: 
                     26: static bool StrEqNc(const char *s1, const char *s2, bool strict) {
                     27:        while(true) {
                     28:                if(!(*s1)) {
                     29:                        if(!(*s2))
                     30:                                return true;
                     31:                        else
                     32:                                return !strict;
                     33:                } else if(!(*s2))
                     34:                        return !strict;
                     35:                if(isalpha(*s1)) {
                     36:                        if(tolower(*s1) !=tolower(*s2))
                     37:                                return false;
                     38:                } else if((*s1) !=(*s2))
                     39:                        return false;
                     40:                s1++;
                     41:                s2++;
                     42:        }
                     43: }
                     44: 
1.16    ! paf        45: static size_t getHeader(const char *data,size_t len){
        !            46:     size_t i,enter=-1;
1.3       paf        47:     if (data)
                     48:        for (i=0;i<len;i++)
                     49:            if (data[i]=='\n'){
                     50:                if (enter>=0) enter++;
                     51:                if (enter>1) return i;
                     52:            } else if (data[i]!='\r') enter=0;
                     53:     return 0;
                     54: }
                     55: 
1.16    ! paf        56: static const char *searchAttribute(const char *data,const char *attr,size_t len){
        !            57:     size_t i;
1.3       paf        58:     if (data)
                     59:        for (i=0;i<len;i++)
                     60:            if (tolower(data[i])==*attr){
1.16    ! paf        61:                size_t j;
1.3       paf        62:                for (j=i+1;j<=len;j++)
                     63:                    if (!attr[j-i]) return &data[j];
                     64:                    else {
                     65:                        if (j==len) break;
                     66:                        if (attr[j-i]!=tolower(data[j])) break;
                     67:                    }
                     68:            }
                     69:     return NULL;
                     70: }
                     71: 
                     72: // VForm
                     73: 
1.16    ! paf        74: char *VForm::strpart(const char *str, size_t len) {
1.7       paf        75:     char *result=(char *)malloc(len+1);
1.3       paf        76:     if (!result) return NULL;
                     77:     memcpy(result,str,len);
                     78:     result[len]=0;
                     79:     return result;
                     80: }
                     81: 
1.16    ! paf        82: char *VForm::getAttributeValue(const char *data,char *attr,size_t len) {
1.3       paf        83:     const char *value=searchAttribute(data,attr,len);
                     84:     if (value){
1.16    ! paf        85:        size_t i;
1.3       paf        86:        if (!(len-=value-data)) return NULL;
                     87:        if (*value=='"') {
                     88:            for (i=1;i<len;i++) if (value[i]=='"') break;
                     89:            return strpart(&value[1],i-1);
                     90:        } else {
                     91:            for (i=0;i<len;i++) if (strchr(" ;\"\n\r",value[i])) break;
                     92:            return strpart(value,i);
                     93:        }
                     94:     }
                     95:     return NULL;
                     96: }
                     97: 
                     98: void VForm::ParseGetFormInput(const char *query_string) {
                     99:        ParseFormInput(query_string, strlen(query_string));
                    100: }
                    101: 
1.16    ! paf       102: void VForm::ParsePostFormInput(const char *content_type, size_t post_size, 
1.3       paf       103:                                                           bool mime_mode) {
                    104:        char *input;
                    105:        if(!post_size) 
                    106:                return;
                    107: 
                    108:        input=(char *) malloc(post_size);
1.16    ! paf       109:        size_t read_size=SAPI::read_post(pool(), input, post_size);
1.12      paf       110:        if(read_size!=post_size)
1.3       paf       111:                THROW(0, 0,
                    112:                        0,
                    113:                        "ParsePostFormInput: post_size(%d)!=read_size(%d)", 
                    114:                                post_size, read_size);
                    115: 
                    116:        if(mime_mode)
                    117:                ParseMimeInput(content_type, input, post_size);
                    118:        else
                    119:                ParseFormInput(input, post_size);
                    120: }
                    121: 
1.16    ! paf       122: void VForm::ParseFormInput(const char *data, size_t length) {
1.8       paf       123:        /* Scan for pairs, unescaping and storing them as they are found. */
1.16    ! paf       124:        size_t pos=0;
1.3       paf       125:        while(pos !=length) {
1.16    ! paf       126:                size_t foundEq=0;
        !           127:                size_t foundAmp=0;
        !           128:                size_t start=pos;
        !           129:                size_t len=0;
1.3       paf       130:                while(pos !=length) {
                    131:                        if(data[pos]=='=') {
                    132:                                foundEq=1;
                    133:                                pos++;
                    134:                                break;
                    135:                        }
                    136:                        pos++;
                    137:                        len++;
                    138:                }
                    139:                if(!foundEq)
                    140:                        break;
1.6       paf       141:                const char *attr=unescape_chars(pool(), data+start, len);
1.3       paf       142:                start=pos;
                    143:                len=0;
                    144:                while(pos !=length) {
                    145:                        if(data[pos]=='&') {
                    146:                                foundAmp=1;
                    147:                                pos++;
                    148:                                break;
                    149:                        }
                    150:                        pos++;
                    151:                        len++;
                    152:                }
                    153:                /* The last pair probably won't be followed by a &, but
                    154:                        that's fine, so check for that after accepting it */
1.6       paf       155:                const char *value=unescape_chars(pool(), data+start, len);
1.3       paf       156:                /* OK, we have a new pair, add it to the list. */
                    157:                AppendFormEntry(attr, value);
                    158:                if(!foundAmp)
                    159:                        break;
                    160:        }
                    161: }
                    162: 
                    163: void VForm::ParseMimeInput(const char *content_type, 
1.16    ! paf       164:                                                   const char *data, size_t length) {
1.3       paf       165: /* Scan for mime-presented pairs, storing them as they are found. */
                    166:        const char 
                    167:                *boundary=getAttributeValue(content_type,"boundary=",strlen(content_type)),
                    168:            *lastData=&data[length];
                    169:        if(!boundary) 
                    170:                THROW(0,0,
                    171:                        0,
                    172:                        "VForm::ParseMimeInput no boundary attribute of Content-Type");
                    173: 
                    174:        while(true) {
                    175:                const char 
                    176:                        *dataStart=searchAttribute(data,boundary,lastData-data),
                    177:                        *dataEnd=searchAttribute(dataStart,boundary,lastData-dataStart);
1.16    ! paf       178:                size_t headerSize=getHeader(dataStart,lastData-dataStart);
1.3       paf       179: 
                    180:                if(!dataStart|!dataEnd|!headerSize) break;
                    181:                if(searchAttribute(dataStart,"content-disposition: form-data",headerSize)){
1.16    ! paf       182:                        size_t valueSize=(dataEnd-dataStart)-headerSize-5-strlen(boundary);
1.3       paf       183:                        char *attr=getAttributeValue(dataStart," name=",headerSize),
                    184:                             *fName=getAttributeValue(dataStart," filename=",headerSize);
                    185: 
                    186:                        if(attr && valueSize){
                    187:                                /* OK, we have a new pair, add it to the list. */
                    188:                                AppendFormEntry(attr, &dataStart[headerSize+1], valueSize, fName);
                    189:                        }
                    190:                }
                    191:                data=(dataEnd-strlen(boundary));
                    192:        }
                    193: }
                    194: 
1.7       paf       195: void VForm::AppendFormEntry(const char *aname, 
1.16    ! paf       196:                                                        const char *value_ptr, size_t value_size,
1.3       paf       197:                                                        const char *file_name) {
1.7       paf       198:        String& sname=*NEW String(pool(), aname);
1.3       paf       199: 
                    200:        Value *value;
                    201:        if(file_name)
1.9       paf       202:                value=NEW VFile(pool(), 
                    203:                        value_ptr, value_size,
                    204:                        file_name);
1.3       paf       205:        else {
                    206:                String& string=*NEW String(pool());
                    207:                string.APPEND_TAINTED(value_ptr, value_size, "form", 0);
                    208:                value=NEW VString(string);
                    209:        }
                    210: 
                    211:        fields.put(sname, value);
                    212: }
1.1       paf       213: 
1.16    ! paf       214: void VForm::fill_fields(Request& request, size_t post_max_size) {
1.3       paf       215:        // parsing QS [GET and ?name=value from uri rewrite)]
                    216:        if(request.info.query_string)
                    217:                ParseGetFormInput(request.info.query_string);
                    218:        // parsing POSTed data
1.4       paf       219:        if(request.info.method) {
1.3       paf       220:                if(const char *content_type=request.info.content_type)
1.4       paf       221:                        if(StrEqNc(request.info.method, "post",true)) {
1.16    ! paf       222:                                size_t post_size=max(0, min(request.info.content_length, post_max_size));
1.3       paf       223:                                if(StrEqNc(content_type, "application/x-www-form-urlencoded",true)) 
                    224:                                        ParsePostFormInput(content_type, post_size, false);
                    225:                                else if(StrEqNc(content_type, "multipart/form-data",0))
                    226:                                        ParsePostFormInput(content_type, post_size, true);
                    227:                        }
                    228:        } else
                    229:                ; // TODO: разобрать пришедшее письмо, если какой ключик выставлен?
1.1       paf       230: }

E-mail: