/* * Portions taken from libapreq 1.33. * Copyright 2007 The Apache Software Foundation. * Used under the Apache License v2.0. * http://search.cpan.org/~stas/libapreq-1.33/ */ #ifndef __USE_GNU #define __USE_GNU #endif #include #include #include #include #include "parser.h" static void req_plustospace(char* str) { register int x; for(x=0;str[x];x++) if(str[x] == '+') str[x] = ' '; } static char x2c(char* what) { register char digit; digit = ((what[0] >= 'A') ? ((what[0] & 0xdf) - 'A') + 10 : (what[0] - '0')); digit *= 16; digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A') + 10 : (what[1] - '0')); return digit; } static unsigned int utf8_convert(char* str) { long x = 0; int i = 0; while (i < 4 ) { if ( isxdigit(str[i]) != 0 ) { if( isdigit(str[i]) != 0 ) { x = x * 16 + str[i] - '0'; } else { str[i] = tolower( str[i] ); x = x * 16 + str[i] - 'a' + 10; } } else { return 0; } i++; } if(i < 3) return 0; return (x); } static int unescape_url_u(char* url) { register int x, y, badesc, badpath; badesc = 0; badpath = 0; for (x = 0, y = 0; url[y]; ++x, ++y) { if (url[y] != '%'){ url[x] = url[y]; } else { if(url[y + 1] == 'u' || url[y + 1] == 'U'){ unsigned int c = utf8_convert(&url[y + 2]); y += 5; if(c < 0x80){ url[x] = c; } else if(c < 0x800) { url[x] = 0xc0 | (c >> 6); url[++x] = 0x80 | (c & 0x3f); } else if(c < 0x10000){ url[x] = (0xe0 | (c >> 12)); url[++x] = (0x80 | ((c >> 6) & 0x3f)); url[++x] = (0x80 | (c & 0x3f)); } else if(c < 0x200000){ url[x] = 0xf0 | (c >> 18); url[++x] = 0x80 | ((c >> 12) & 0x3f); url[++x] = 0x80 | ((c >> 6) & 0x3f); url[++x] = 0x80 | (c & 0x3f); } else if(c < 0x4000000){ url[x] = 0xf8 | (c >> 24); url[++x] = 0x80 | ((c >> 18) & 0x3f); url[++x] = 0x80 | ((c >> 12) & 0x3f); url[++x] = 0x80 | ((c >> 6) & 0x3f); url[++x] = 0x80 | (c & 0x3f); } else if(c < 0x8000000){ url[x] = 0xfe | (c >> 30); url[++x] = 0x80 | ((c >> 24) & 0x3f); url[++x] = 0x80 | ((c >> 18) & 0x3f); url[++x] = 0x80 | ((c >> 12) & 0x3f); url[++x] = 0x80 | ((c >> 6) & 0x3f); url[++x] = 0x80 | (c & 0x3f); } } else { if (!isxdigit(url[y + 1]) || !isxdigit(url[y + 2])) { badesc = 1; url[x] = '%'; } else { url[x] = x2c(&url[y + 1]); y += 2; if (url[x] == '/' || url[x] == '\0') badpath = 1; } } } } url[x] = '\0'; if (badesc) return 0; else if (badpath) return 0; else return 1; } static char* _strndup(char* str, size_t len) { char *dup = (char*) malloc(len+1); if (dup) { strncpy(dup, str, len); dup[len] = '\0'; } return dup; } static char* urlword(char** line) { char* res = 0; char* pos = *line; char ch; while ( (ch = *pos) != '\0' && ch != ';' && ch != '&') { ++pos; } res = _strndup(*line, pos - *line); while (ch == ';' || ch == '&') { ++pos; ch = *pos; } *line = pos; return res; } char* getword(char** line, char stop) { char* pos = *line; int len; char* res; while ((*pos != stop) && *pos) { ++pos; } len = pos - *line; res = (char*)malloc(len + 1); memcpy(res, *line, len); res[len] = 0; if (stop) { while (*pos == stop) { ++pos; } } *line = pos; return res; } SV* _split_to_parms(char* data) { char* val; HV* hash = 0; while (*data && (val = urlword(&data))) { char* val_orig = val; char* key = getword(&val, '='); req_plustospace((char*)key); unescape_url_u((char*)key); req_plustospace((char*)val); unescape_url_u((char*)val); if (!hash) { hash = newHV(); } int klen = strlen(key); SV* newval = newSVpv(val, 0); if (hv_exists(hash, key, klen)) { /* this param already exists */ SV** entry = hv_fetch(hash, key, klen, 0); if (!entry) { return 0; } if (SvROK(*entry) && SvTYPE(SvRV(*entry)) == SVt_PVAV) { /* already an arrayref, just push to the end */ av_push((AV*) SvRV(*entry), newval); } else { /* just a scalar; wrap the new and old values in an arrayref */ SV* values[2] = { *entry, newval }; AV* array = av_make(2, values); /* this copies the SVs... */ SvREFCNT_dec(newval); /* ... so destroy the original. */ SV* aref = newRV_noinc((SV*) array); /* create an array ref... */ hv_store(hash, key, klen, aref, 0); /* ... and stash it in the hash */ } } else { /* no existing param, pop this one in */ hv_store(hash, key, klen, newval, 0); } free(key); free(val_orig); } return hash ? newRV_noinc((SV*) hash) : 0; }