qbool HTTPSV_GetHeaderField(const char *s, const char *field, char *buffer, int buffersize) { char *start = NULL; char *end = NULL; char *copy = NULL; char *colon = NULL; qbool status = false; int fieldnamelen = strlen(field); #define EAT_WHITESPACE(str) while (*str && (*str == ' ' || *str == '\t')) str++; buffer[0] = 0; copy = Sys_strdup(s); start = end = copy; while (*end) { if (*end == '\n') { *end = '\0'; colon = strchr(start, ':'); if (!colon) { // Header exists, but has no value. (Not sure if this is proper according to RFC). if (!strncmp(field, start, fieldnamelen)) { if (start[fieldnamelen] <= ' ') { status = true; break; } } } else { if (fieldnamelen == colon - start) { if (!strncmp(field, start, colon - start)) { colon++; EAT_WHITESPACE(colon); while (--buffersize > 0) { if (*colon == '\r' || *colon == '\n') break; *buffer++ = *colon++; } *buffer = 0; status = true; break; } } } start = end + 1; } end++; } Sys_free(copy); return status; }
qbool Info_Set (ctxinfo_t *ctx, const char *name, const char *value) { info_t *a; int key; if (!value) value = ""; if (!ctx || !name || !name[0]) return false; if (strchr(name, '\\') || strchr(value, '\\')) return false; if (strchr(name, 128 + '\\') || strchr(value, 128 + '\\')) return false; if (strchr(name, '"') || strchr(value, '"')) return false; if (strchr(name, '\r') || strchr(value, '\r')) // bad for print functions return false; if (strchr(name, '\n') || strchr(value, '\n')) // bad for print functions return false; if (strchr(name, '$') || strchr(value, '$')) // variable expansion may be exploited, escaping this return false; if (strchr(name, ';') || strchr(value, ';')) // interpreter may be haxed, escaping this return false; if (strlen(name) >= MAX_INFO_KEY || strlen(value) >= MAX_INFO_KEY) return false; // too long name/value, its wrong key = Sys_HashKey(name) % INFO_HASHPOOL_SIZE; // if already exists, reuse it for (a = ctx->info_hash[key]; a; a = a->hash_next) if (!stricmp(name, a->name)) { Sys_free (a->value); break; } // not found, create new one if (!a) { if (ctx->cur >= ctx->max) return false; // too much infos a = (info_t *) Sys_malloc (sizeof(info_t)); a->next = ctx->info_list; ctx->info_list = a; a->hash_next = ctx->info_hash[key]; ctx->info_hash[key] = a; ctx->cur++; // increase counter // copy name a->name = Sys_strdup (name); } // copy value #if 0 { // unfortunatelly evil users use non printable/control chars, so that does not work well a->value = Sys_strdup (value); } #else { // skip some control chars, doh char v_buf[MAX_INFO_KEY] = {0}, *v = v_buf; int i; for (i = 0; value[i]; i++) // len of 'value' should be less than MAX_INFO_KEY according to above checks { if ((unsigned char)value[i] > 13) *v++ = value[i]; } *v = 0; a->value = Sys_strdup (v_buf); } #endif // hrm, empty value, remove it then if (!a->value[0]) { return Info_Remove(ctx, name); } return true; }