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