pp->client_output.end = dest;
pp->output.end = dest;
static int convert_cgi_headers(struct pipe_params *pp, int *sp){	int addheader, c, s, l;	size_t i, nheaders, status, location, length;	const char *p, *tmpname, *tmpvalue;	int havestatus, havelocation, firstline, havelength;	size_t len, tmpnamelen, tmpvaluelen;	char buf[50], gbuf[40], *cp, *dest;	unsigned long ul;	nheaders = 0;	tmpname = 0;	tmpnamelen = 0;	tmpvalue = 0;	havestatus = 0;	havelocation = 0;	havelength = 0;	status = 0;	location = 0;	length = 0;	s = 0;	len = 0;	addheader = 0;	firstline = 1;	for (p = pp->script_input.floor; p < pp->script_input.start; p++) {		c = *p;		switch (s) {		case 0:			switch (c) {			case '\r':			case '\n':				break;			default:				tmpname = p;				tmpnamelen = 0;				tmpvalue = 0;				len = 0;				s = 1;				break;			}			break;		case 1:			++len;			switch (c) {			case '\r':			case '\n':				addheader = 1;				s = 0;				break;			case ':':			case ' ':			case '\t':				if (tmpnamelen == 0)					tmpnamelen = len;				break;			default:				if (tmpnamelen && tmpvalue == 0)					tmpvalue = p;				break;			}			break;		}		if (addheader) {			if (tmpvalue == 0)				addheader = 0;			else if (firstline && tmpnamelen >= 8 && strncmp(tmpname, "HTTP/", 5) == 0) {				status = nheaders;				havestatus = 1;			} else				switch (tmpnamelen) {				case 4:					if (strncasecmp(tmpname, "Date", 4) == 0)						addheader = 0;					break;				case 6:					if (strncasecmp(tmpname, "Server", 6) == 0)						addheader = 0;					else if (strncasecmp(tmpname, "Status", 6) == 0) {						if (havestatus)							addheader = 0;						else {							status = nheaders;							havestatus = 1;						}					}					break;				case 8:					if (strncasecmp(tmpname, "Location", 8) == 0) {						if (havelocation)							addheader = 0;						else {							location = nheaders;							havelocation = 1;						}					}					break;				case 10:					if (strncasecmp(tmpname, "Connection", 10) == 0)						addheader = 0;					break;				case 14:					if (strncasecmp(tmpname, "Content-Length", 14) == 0) {						if (havelength)							addheader = 0;						else {							length = nheaders;							havelength = 1;						}					}					break;				case 17:					if (strncasecmp(tmpname, "Transfer-Encoding", 17) == 0) {						log_d("convert_cgi_headers: script sent Transfer-Encoding!?!?");						return -1;					}					break;				}			if (firstline)				firstline = 0;			if (addheader == 0)				log_d("convert_cgi_headers: disallowing header \"%.*s\"", len, tmpname);			else {				if (nheaders >= tuning.num_headers) {					log_d("convert_cgi_headers: too many header lines");					return -1;				}				cgi_headers[nheaders].name = tmpname;				cgi_headers[nheaders].value = tmpvalue;				cgi_headers[nheaders].namelen = tmpnamelen;				cgi_headers[nheaders++].len = len;				addheader = 0;			}		}	}	if (s) {		log_d("convert_cgi_headers: s=%d!?", s);		return -1;	}	dest = pp->client_output.floor;	if (havelocation && havestatus == 0) {		if (dest + 20 > pp->client_output.ceiling)			return no_room();		s = 302;		memcpy(dest, "HTTP/1.1 302 Moved\r\n", 20);		dest += 20;	} else if (havestatus == 0) {		if (dest + 17 > pp->client_output.ceiling)			return no_room();		s = 200;		memcpy(dest, "HTTP/1.1 200 OK\r\n", 17);		dest += 17;	} else {		s = atoi(cgi_headers[status].value);		if (s < 200 || s > 599) {			log_d("convert_cgi_headers: illegal header line \"%.*s\"", cgi_headers[status].len, cgi_headers[status].name);			return -1;		}		if (s == 204 || s == 304) {			if (havelength) {				log_d("convert_cgi_headers: script should not send content-length with status %d", s);				return -1;			}			pp->nocontent = 1;			pp->chunkit = 0;		}		tmpvaluelen = cgi_headers[status].len - (cgi_headers[status].value - cgi_headers[status].name);		if (dest + tmpvaluelen + 11 > pp->client_output.ceiling)			return no_room();		memcpy(dest, "HTTP/1.1 ", 9);		dest += 9;		memcpy(dest, cgi_headers[status].value, tmpvaluelen);		dest += tmpvaluelen;		*dest++ = '\r';		*dest++ = '\n';	}	if (havelength) {		tmpvalue = cgi_headers[length].value;		if (*tmpvalue == '-') {			log_d("convert_cgi_headers: illegal content-length header \"%.*s\"", cgi_headers[length].len, cgi_headers[length].name);			return -1;		}		ul = strtoul(tmpvalue, &cp, 10);		if (cp != tmpvalue) {			while (*cp != '\n' && (*cp == ' ' || *cp == '\t' || *cp == '\r'))				++cp;		}		if (*cp != '\n' || ul >= UINT_MAX) {			log_d("convert_cgi_headers: illegal content-length header \"%.*s\"", cgi_headers[length].len, cgi_headers[length].name);			return -1;		}		pp->chunkit = 0;		pp->haslen = 1;		pp->pmax = ul;		pp->cn->r->num_content = 0;		pp->cn->r->content_length = ul;	} else if (pp->cn->r->protocol_minor == 0 && pp->nocontent == 0)		pp->cn->keepalive = 0;	l = sprintf(buf, "Server: %.30s\r\n", server_version);	if (dest + l > pp->client_output.ceiling)		return no_room();	memcpy(dest, buf, l);	dest += l;	l = sprintf(buf, "Date: %s\r\n", rfctime(current_time, gbuf));	if (dest + l > pp->client_output.ceiling)		return no_room();	memcpy(dest, buf, l);	dest += l;	if (pp->chunkit) {		l = sprintf(buf, "Transfer-Encoding: chunked\r\n");		if (dest + l > pp->client_output.ceiling)			return no_room();		memcpy(dest, buf, l);		dest += l;	}	if (pp->cn->r->protocol_minor == 0 && pp->cn->keepalive) {		l = sprintf(buf, "Connection: keep-alive\r\n");		if (dest + l > pp->client_output.ceiling)			return no_room();		memcpy(dest, buf, l);		dest += l;	}	if (pp->cn->r->protocol_minor && pp->cn->keepalive == 0) {		l = sprintf(buf, "Connection: close\r\n");		if (dest + l > pp->client_output.ceiling)			return no_room();		memcpy(dest, buf, l);		dest += l;	}	for (i = 0; i < nheaders; i++) {		if (havestatus == 0 || i != status) {			if (dest + cgi_headers[i].len + 2 > pp->client_output.ceiling)				return no_room();			memcpy(dest, cgi_headers[i].name, cgi_headers[i].len);			dest += cgi_headers[i].len;			*dest++ = '\r';			*dest++ = '\n';		}	}	if (dest + 2 > pp->client_output.ceiling)		return no_room();	*dest++ = '\r';	*dest++ = '\n';	pp->client_output.end = dest;	*sp = s;	return 0;}