#include #include #include #include #include "cforum.h" /* Return an allocated string containing the next cookie ("name=value"). */ char * nextcookie(int max) { char *buf; int n; static char *cs = NULL; if(!(buf = malloc(max))) err(1, "malloc"); if(!cs) cs = getenv("HTTP_COOKIE"); if(!cs || !*cs) return NULL; if(*cs == ' ') cs++; n = strcspn(cs, ";"); snprintf(buf, max, "%.*s", n, cs); cs += n + (n != strlen(cs)); return buf; } /* * Return an allocated string containing the next parameter ("key=value"). * The method argument decides which data (GET or POST) to read from. * * If len is NULL, the string will be NUL-terminated; if len is non-NULL, * the string will not be NUL-terminated, and len will be pointed to the * length of the string. * * The string is truncated to max characters. If truncation occurred, the * -1th character of the string is set to 1. */ char * nextparam(enum method method, int *len, int max) { char *buf; int i, sz; static int j = 0; /* Return NULL if at end of parameter string. */ if(method == GET && !query.string[j-1]) return NULL; #define STEP 256 sz = STEP; if(!(buf = malloc(1+sz))) /* Leave space for -1th character. */ err(1, "malloc"); /* * buf's -1th character is set to 1 if the string * has been truncated (i.e. if input exceeded max). */ buf++; TRUNCATED(buf) = 0; #define READ(b) (method == GET? \ (*(b) = query.string[j++]): \ fread(b, 1, 1, stdin)) /* * The parameter is read in a rather lopsided loop, treating * the first character specially. */ first: /* Return NULL if at end of parameter string. */ if(!READ(buf)) return NULL; /* Skip empty parameters. */ if(*buf == '&') goto first; i = 0; goto rest; for(; READ(buf+i); i++){ rest: if(buf[i] == '&'){ buf[i] = 0; break; } if(i+1 > max){ TRUNCATED(buf) = 1; /* Skip ahead to next parameter. */ while(READ(buf+i+1) && buf[i+1] != '&') ; break; } if(i+1 >= sz){ sz += STEP; /* Remember to adjust for -1th character. */ if(buf--, buf = realloc(buf, 1+sz), !buf++) err(1, "realloc"); } } if(len) *len = i; else buf[i] = 0; return buf; } /* Fill global query structure from CGI environment variables. */ void setquery() { query.string = getenv("QUERY_STRING"); if(!query.string){ fprintf(stderr, "no QUERY_STRING\n"); exit(1); } query.method = strcmp(getenv("REQUEST_METHOD"), "POST")? GET: POST; if(query.method == POST) query.length = atoi(getenv("CONTENT_LENGTH")); } /* * Split parameter string on equals sign and return value portion; * return NULL if none found. For example, v = split(p) results in * p pointing to the parameter key and v pointing to the value. */ char * split(char *param) { int n; n = strcspn(param, "="); if(!param[n]) return NULL; param[n] = 0; return param+n+1; } /* * Decode a URL-encoded string in place. If len is negative, the string * is assumed to be NUL-terminated. The length of the new string is * returned. Note that the new string is NOT NUL-terminated! To produce * a NUL-terminated string, use s[urldecode(s, -1)] = 0. */ int urldecode(char *s, int len) { unsigned int code, i, j; if(len < 0) len = strlen(s); for(i = j = 0; i < len; i++, j++){ if(s[i] == '+') s[j] = ' '; else if(s[i] == '%'){ if(!sscanf(s+i+1, "%2x", &code)) code = '?'; s[j] = code; i += 2; }else s[j] = s[i]; } return j; }