17c478bdstevel@tonic-gate/*
27c478bdstevel@tonic-gate * CDDL HEADER START
37c478bdstevel@tonic-gate *
47c478bdstevel@tonic-gate * The contents of this file are subject to the terms of the
52c9e429brutus * Common Development and Distribution License (the "License").
62c9e429brutus * You may not use this file except in compliance with the License.
77c478bdstevel@tonic-gate *
87c478bdstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bdstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bdstevel@tonic-gate * See the License for the specific language governing permissions
117c478bdstevel@tonic-gate * and limitations under the License.
127c478bdstevel@tonic-gate *
137c478bdstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bdstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bdstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bdstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bdstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bdstevel@tonic-gate *
197c478bdstevel@tonic-gate * CDDL HEADER END
207c478bdstevel@tonic-gate */
217c478bdstevel@tonic-gate/*
22d3d5073Rafael Vanoni * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bdstevel@tonic-gate * Use is subject to license terms.
247c478bdstevel@tonic-gate */
257c478bdstevel@tonic-gate
267c478bdstevel@tonic-gate#include <sys/sysmacros.h>
277c478bdstevel@tonic-gate#include <sys/strsubr.h>
287c478bdstevel@tonic-gate#include <fs/sockfs/nl7c.h>
297c478bdstevel@tonic-gate#include <fs/sockfs/nl7curi.h>
300f1702cYu Xiangning<Eric.Yu@Sun.COM>#include <fs/sockfs/socktpi.h>
317c478bdstevel@tonic-gate
327c478bdstevel@tonic-gate#include <inet/nca/ncadoorhdr.h>
337c478bdstevel@tonic-gate#include <inet/nca/ncalogd.h>
347c478bdstevel@tonic-gate
352c9e429brutus
362c9e429brutusvolatile uint64_t	nl7c_http_response_chunked = 0;
372c9e429brutusvolatile uint64_t	nl7c_http_response_chunkparse = 0;
382c9e429brutus
392c9e429brutusvolatile uint64_t	nl7c_http_response_pass1 = 0;
402c9e429brutusvolatile uint64_t	nl7c_http_response_pass2 = 0;
412c9e429brutusvolatile uint64_t	nl7c_http_response_304 = 0;
422c9e429brutusvolatile uint64_t	nl7c_http_response_307 = 0;
432c9e429brutusvolatile uint64_t	nl7c_http_response_400 = 0;
442c9e429brutus
452c9e429brutusvolatile uint64_t	nl7c_http_cond_304 = 0;
462c9e429brutusvolatile uint64_t	nl7c_http_cond_412 = 0;
472c9e429brutus
482c9e429brutus/*
492c9e429brutus * Some externs:
502c9e429brutus */
512c9e429brutus
522c9e429brutusextern uint64_t		nl7c_uri_bytes;
532c9e429brutusextern kmem_cache_t	*nl7c_uri_kmc;
542c9e429brutusextern kmem_cache_t	*nl7c_uri_rd_kmc;
552c9e429brutusextern void		nl7c_uri_inactive(uri_desc_t *);
562c9e429brutusextern uint32_t		nca_major_version;
572c9e429brutusextern uint32_t		nca_minor_version;
582c9e429brutus
597c478bdstevel@tonic-gate/*
607c478bdstevel@tonic-gate * HTTP connection persistent headers, mblk_t's, and state values stored in
617c478bdstevel@tonic-gate * (struct sonode *).so_nl7c_flags & NL7C_SCHEMEPRIV.
627c478bdstevel@tonic-gate */
637c478bdstevel@tonic-gate
647c478bdstevel@tonic-gatechar	Shttp_conn_cl[] = "Connection: close\r\n";
657c478bdstevel@tonic-gatechar	Shttp_conn_ka[] = "Connection: Keep-Alive\r\n";
667c478bdstevel@tonic-gate
677c478bdstevel@tonic-gatemblk_t	*http_conn_cl;
687c478bdstevel@tonic-gatemblk_t	*http_conn_ka;
697c478bdstevel@tonic-gate
707c478bdstevel@tonic-gate#define	HTTP_CONN_CL	0x00010000
717c478bdstevel@tonic-gate#define	HTTP_CONN_KA	0x00020000
727c478bdstevel@tonic-gate
737c478bdstevel@tonic-gate/*
742c9e429brutus * Hex ascii Digit to Integer accumulate, if (char)c is a valid ascii
752c9e429brutus * hex digit then the contents of (int32_t)n will be left shifted and
762c9e429brutus * the new digit added in, else n will be set to -1.
777c478bdstevel@tonic-gate */
787c478bdstevel@tonic-gate
792c9e429brutus#define	hd2i(c, n) {							\
802c9e429brutus	(n) *= 16;							\
812c9e429brutus	if (isdigit(c))							\
822c9e429brutus		(n) += (c) - '0';					\
832c9e429brutus	else if ((c) >= 'a' && (c) <= 'f')				\
842c9e429brutus		(n) += (c) - 'W';					\
852c9e429brutus	else if ((c) >= 'A' && (c) <= 'F')				\
862c9e429brutus		(n) += (c) - '7';					\
872c9e429brutus	else								\
882c9e429brutus		(n) = -1;						\
892c9e429brutus}
907c478bdstevel@tonic-gate
917c478bdstevel@tonic-gate/*
927c478bdstevel@tonic-gate * HTTP parser action values:
937c478bdstevel@tonic-gate */
947c478bdstevel@tonic-gate
957c478bdstevel@tonic-gatetypedef enum act_e {
967c478bdstevel@tonic-gate	REQUEST		= 0x0001,
977c478bdstevel@tonic-gate	NUMERIC		= 0x0002,
987c478bdstevel@tonic-gate	QUALIFIER	= 0x0004,
997c478bdstevel@tonic-gate	PASS		= 0x0008,
1007c478bdstevel@tonic-gate	FILTER		= 0x0010,
1017c478bdstevel@tonic-gate	NOCACHE		= 0x0020,
1027c478bdstevel@tonic-gate	HASH		= 0x0040,
1037c478bdstevel@tonic-gate	DATE		= 0x0080,
1047c478bdstevel@tonic-gate	ETAG		= 0x0100,
1057c478bdstevel@tonic-gate	RESPONSE	= 0x0200,
1067c478bdstevel@tonic-gate	URIABS		= 0x0400,
1072c9e429brutus	URIREL		= 0x0800,
1082c9e429brutus	HEX		= 0x1000
1097c478bdstevel@tonic-gate} act_t;
1107c478bdstevel@tonic-gate
1117c478bdstevel@tonic-gate#define	UNDEF		PASS
1127c478bdstevel@tonic-gate
1137c478bdstevel@tonic-gate/*
1147c478bdstevel@tonic-gate * HTTP parser token:
1157c478bdstevel@tonic-gate */
1167c478bdstevel@tonic-gate
1177c478bdstevel@tonic-gatetypedef struct token_s {
1187c478bdstevel@tonic-gate	int	tokid;			/* Token ident */
1197c478bdstevel@tonic-gate	char	*text;			/* Token text */
1207c478bdstevel@tonic-gate	act_t	act;			/* Action to take */
1217c478bdstevel@tonic-gate} token_t;
1227c478bdstevel@tonic-gate
1237c478bdstevel@tonic-gate/*
1247c478bdstevel@tonic-gate * The ttree_t (or token tree) is an ascending ordered binary tree
1257c478bdstevel@tonic-gate * built by ttree_build() from an array of tokens and subsequently
1267c478bdstevel@tonic-gate * used by ttree_line_parse() to parse multiline text data.
1277c478bdstevel@tonic-gate */
1287c478bdstevel@tonic-gatetypedef struct ttree_s {
1297c478bdstevel@tonic-gate	token_t *tok;			/* Token */
1307c478bdstevel@tonic-gate	struct ttree_s *lt, *gt;	/* < and > next node */
1317c478bdstevel@tonic-gate} ttree_t;
1327c478bdstevel@tonic-gate
1337c478bdstevel@tonic-gate/*
1347c478bdstevel@tonic-gate * Note: req_tree[] and res_tree[] must be in ascending case insensitive
1357c478bdstevel@tonic-gate * order of the char[] strings used to initialize each element.
1367c478bdstevel@tonic-gate *
1377c478bdstevel@tonic-gate * See "nl7ctokreq.txt" and "nl7ctokres.txt" which are processed by
1387c478bdstevel@tonic-gate * "nl7ctokgen" to produce "nl7ctokgen.h" and included here.
1397c478bdstevel@tonic-gate */
1407c478bdstevel@tonic-gate
1417c478bdstevel@tonic-gate#define	INIT(s, t) {s, S##s, t}
1427c478bdstevel@tonic-gate
1437c478bdstevel@tonic-gate#include "nl7ctokgen.h"
1447c478bdstevel@tonic-gatestatic ttree_t *req_tree;
1457c478bdstevel@tonic-gatestatic ttree_t *res_tree;
1467c478bdstevel@tonic-gate
1477c478bdstevel@tonic-gate/*
1482c9e429brutus * HTTP scheme private state:
1492c9e429brutus */
1502c9e429brutus
1512c9e429brutustypedef struct http_s {
1522c9e429brutus	boolean_t	parsed;		/* Response parsed */
1532c9e429brutus	uint32_t	major, minor;	/* HTTP/major.minor */
1542c9e429brutus	uint32_t	headlen;	/* HTTP header length */
1552c9e429brutus	clock_t		date;		/* Response Date: */
1562c9e429brutus	clock_t		expire;		/* Response Expire: */
1572c9e429brutus	clock_t		moddate;	/* Request *Modified-Since date */
1582c2d21eRichard Lowe	enum tokid_e	modtokid;	/* Request *Modified-Since tokid */
1592c9e429brutus	time_t		lastmod;	/* Response Last-Modified: */
1602c9e429brutus	str_t		accept;		/* Request Accept: */
1612c9e429brutus	str_t		acceptchar;	/* Request Accept-Charset: */
1622c9e429brutus	str_t		acceptenco;	/* Request Accept-Encoding: */
1632c9e429brutus	str_t		acceptlang;	/* Request Accept-Language: */
1642c9e429brutus	str_t		etag;		/* Request/Response ETag: */
1652c9e429brutus	str_t		uagent;		/* Request User-Agent: */
1662c9e429brutus} http_t;
1672c9e429brutus
1682c9e429brutusstatic kmem_cache_t *http_kmc;
1692c9e429brutus
1702c9e429brutus/*
1712c9e429brutus * HTTP date routines, dow[] for day of the week, Dow[] for day of the
1722c9e429brutus * week for the Unix epoch (i.e. day 0 is a Thu), months[] for the months
1732c9e429brutus * of the year, and dom[] for day number of the year for the first day
1742c9e429brutus * of each month (non leap year).
1757c478bdstevel@tonic-gate */
1767c478bdstevel@tonic-gate
1777c478bdstevel@tonic-gatestatic char *dow[] = {"sunday", "monday", "tuesday", "wednesday", "thursday",
1787c478bdstevel@tonic-gate	"friday", "saturday", 0};
1797c478bdstevel@tonic-gate
1802c9e429brutusstatic char *Dow[] = {"Thu", "Fri", "Sat", "Sun", "Mon", "Tue", "Wed", 0};
1812c9e429brutus
1827c478bdstevel@tonic-gatestatic char *months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",
1837c478bdstevel@tonic-gate	"Aug", "Sep", "Oct", "Nov", "Dec", 0};
1847c478bdstevel@tonic-gate
1857c478bdstevel@tonic-gatestatic int dom[] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
1867c478bdstevel@tonic-gate
1877c478bdstevel@tonic-gate/*
1887c478bdstevel@tonic-gate * http_date2time_t(const char *) - returns the time(2) value (i.e.
1897c478bdstevel@tonic-gate * the value 0 is Thu, 01 Jan 1970 00:00:00 GMT) for the following
1907c478bdstevel@tonic-gate * time formats used by HTTP request and response headers:
1917c478bdstevel@tonic-gate *
1927c478bdstevel@tonic-gate *	1) Sun, 07 Dec 1998 14:49:37 GMT	; RFC 822, updated by RFC 1123
1937c478bdstevel@tonic-gate *	2) Sunday, 07-Dec-98 14:49:37 GMT	; RFC 850, obsoleted by RFC 1036
1947c478bdstevel@tonic-gate *	3) Sun Nov  7 14:49:37 1998		; ANSI C's asctime() format
1957c478bdstevel@tonic-gate *	4) 60					; Time delta of N seconds
1967c478bdstevel@tonic-gate *
1977c478bdstevel@tonic-gate * On error a time_t value of -1 is returned.
1987c478bdstevel@tonic-gate *
1997c478bdstevel@tonic-gate * All dates are GMT (must be part of the date string for types
2007c478bdstevel@tonic-gate * 1 and 2 and not for type 1).
2017c478bdstevel@tonic-gate *
2027c478bdstevel@tonic-gate * Note, the given mstr_t pointed to by *sp will be modified.
2037c478bdstevel@tonic-gate */
2047c478bdstevel@tonic-gate
2057c478bdstevel@tonic-gatestatic time_t
2067c478bdstevel@tonic-gatehttp_date2time_t(char *cp, char *ep)
2077c478bdstevel@tonic-gate{
2087c478bdstevel@tonic-gate	char	*scp = cp;
2097c478bdstevel@tonic-gate	time_t	secs;
2107c478bdstevel@tonic-gate	char	**tpp;
2117c478bdstevel@tonic-gate	char	*tp;
2127c478bdstevel@tonic-gate	char	c, sc;
2137c478bdstevel@tonic-gate	ssize_t	n;
2147c478bdstevel@tonic-gate
2157c478bdstevel@tonic-gate	ssize_t	zeroleap = 1970 / 4 - 1970 / 100 + 1970 / 400;
2167c478bdstevel@tonic-gate	ssize_t	leap;
2177c478bdstevel@tonic-gate	ssize_t	year;
2187c478bdstevel@tonic-gate	ssize_t	month;
2197c478bdstevel@tonic-gate	ssize_t	day;
2207c478bdstevel@tonic-gate	ssize_t	hour;
2217c478bdstevel@tonic-gate	ssize_t	min;
2227c478bdstevel@tonic-gate	ssize_t	sec;
2237c478bdstevel@tonic-gate
2247c478bdstevel@tonic-gate	/* Parse and skip day-of-week (we don't use it) */
2257c478bdstevel@tonic-gate	tpp = dow;
2267c478bdstevel@tonic-gate	tp = *tpp;
2277c478bdstevel@tonic-gate	n = 0;
2287c478bdstevel@tonic-gate	while (cp < ep) {
2297c478bdstevel@tonic-gate		c = *cp++;
2307c478bdstevel@tonic-gate		if (c == ',' || c == ' ')
2317c478bdstevel@tonic-gate			break;
2327c478bdstevel@tonic-gate		c = tolower(c);
2337c478bdstevel@tonic-gate		if (*tp == 0 || *tp != c) {
2347c478bdstevel@tonic-gate			cp = scp;
2357c478bdstevel@tonic-gate			if ((tp = *++tpp) == NULL)
2367c478bdstevel@tonic-gate				break;
2377c478bdstevel@tonic-gate			continue;
2387c478bdstevel@tonic-gate		}
2397c478bdstevel@tonic-gate		tp++;
2407c478bdstevel@tonic-gate	}
2417c478bdstevel@tonic-gate	if (cp == NULL) {
2427c478bdstevel@tonic-gate		/* Not case 1-3, try 4 */
2437c478bdstevel@tonic-gate		while (cp < ep) {
2447c478bdstevel@tonic-gate			c = *cp;
2457c478bdstevel@tonic-gate			if (isdigit(c)) {
2467c478bdstevel@tonic-gate				cp++;
2477c478bdstevel@tonic-gate				n *= 10;
2487c478bdstevel@tonic-gate				n += c - '0';
2497c478bdstevel@tonic-gate				continue;
2507c478bdstevel@tonic-gate			}
2517c478bdstevel@tonic-gate			/* An invalid date sytax */
2527c478bdstevel@tonic-gate			return (-1);
2537c478bdstevel@tonic-gate		}
2547c478bdstevel@tonic-gate		/* Case 4, delta from current time */
2557c478bdstevel@tonic-gate		return (gethrestime_sec() + n);
2567c478bdstevel@tonic-gate	}
2577c478bdstevel@tonic-gate	if (c == ',') {
2587c478bdstevel@tonic-gate		/* Case 1 or 2, skip <SP> */
2597c478bdstevel@tonic-gate		if (cp == ep)
2607c478bdstevel@tonic-gate			return (-1);
2617c478bdstevel@tonic-gate		c = *cp++;
2627c478bdstevel@tonic-gate		if (c != ' ')
2637c478bdstevel@tonic-gate			return (-1);
2647c478bdstevel@tonic-gate		/* Get day of the month */
2657c478bdstevel@tonic-gate		if (cp == ep)
2667c478bdstevel@tonic-gate			return (-1);
2677c478bdstevel@tonic-gate		c = *cp++;
2687c478bdstevel@tonic-gate		if (! isdigit(c))
2697c478bdstevel@tonic-gate			return (-1);
2707c478bdstevel@tonic-gate		n = c - '0';
2717c478bdstevel@tonic-gate		if (cp == ep)
2727c478bdstevel@tonic-gate			return (-1);
2737c478bdstevel@tonic-gate		c = *cp++;
2747c478bdstevel@tonic-gate		if (! isdigit(c))
2757c478bdstevel@tonic-gate			return (-1);
2767c478bdstevel@tonic-gate		n *= 10;
2777c478bdstevel@tonic-gate		n += c - '0';
2787c478bdstevel@tonic-gate		day = n;
2797c478bdstevel@tonic-gate		/* Get day/month/year seperator */
2807c478bdstevel@tonic-gate		if (cp == ep)
2817c478bdstevel@tonic-gate			return (-1);
2827c478bdstevel@tonic-gate		sc = *cp++;
2837c478bdstevel@tonic-gate		if (sc != ' ' && sc != '-')
2847c478bdstevel@tonic-gate			return (-1);
2857c478bdstevel@tonic-gate		/* Parse month */
2867c478bdstevel@tonic-gate		tpp = months;
2877c478bdstevel@tonic-gate		tp = *tpp++;
2887c478bdstevel@tonic-gate		scp = cp;
2897c478bdstevel@tonic-gate		n = 0;
2907c478bdstevel@tonic-gate		while (cp < ep) {
2917c478bdstevel@tonic-gate			c = *cp;
2927c478bdstevel@tonic-gate			if (c == sc) {
2937c478bdstevel@tonic-gate				cp++;
2947c478bdstevel@tonic-gate				break;
2957c478bdstevel@tonic-gate			}
2967c478bdstevel@tonic-gate			c = tolower(c);
2977c478bdstevel@tonic-gate			if (*tp == 0 || tolower(*tp) != c) {
2987c478bdstevel@tonic-gate				if ((tp = *tpp++) == NULL)
2997c478bdstevel@tonic-gate					break;
3007c478bdstevel@tonic-gate				cp = scp;
3017c478bdstevel@tonic-gate				n++;
3027c478bdstevel@tonic-gate				continue;
3037c478bdstevel@tonic-gate			}
3047c478bdstevel@tonic-gate			cp++;
3057c478bdstevel@tonic-gate			tp++;
3067c478bdstevel@tonic-gate		}
3077c478bdstevel@tonic-gate		if (cp == NULL)
3087c478bdstevel@tonic-gate			return (-1);
3097c478bdstevel@tonic-gate		month = n;
3107c478bdstevel@tonic-gate		/* Get year */
3117c478bdstevel@tonic-gate		if (cp == ep)
3127c478bdstevel@tonic-gate			return (-1);
3137c478bdstevel@tonic-gate		c = *cp++;
3147c478bdstevel@tonic-gate		if (! isdigit(c))
3157c478bdstevel@tonic-gate			return (-1);
3167c478bdstevel@tonic-gate		n = c - '0';
3177c478bdstevel@tonic-gate		if (cp == ep)
3187c478bdstevel@tonic-gate			return (-1);
3197c478bdstevel@tonic-gate		c = *cp++;
3207c478bdstevel@tonic-gate		if (! isdigit(c))
3217c478bdstevel@tonic-gate			return (-1);
3227c478bdstevel@tonic-gate		n *= 10;
3237c478bdstevel@tonic-gate		n += c - '0';
3247c478bdstevel@tonic-gate		if (cp == ep)
3257c478bdstevel@tonic-gate			return (-1);
3267c478bdstevel@tonic-gate		c = *cp++;
3277c478bdstevel@tonic-gate		if (sc == ' ') {
3287c478bdstevel@tonic-gate			/* Case 1, get 2 more year digits */
3297c478bdstevel@tonic-gate			if (! isdigit(c))
3307c478bdstevel@tonic-gate				return (-1);
3317c478bdstevel@tonic-gate			n *= 10;
3327c478bdstevel@tonic-gate			n += c - '0';
3337c478bdstevel@tonic-gate			if (cp == ep)
3347c478bdstevel@tonic-gate				return (-1);
3357c478bdstevel@tonic-gate			c = *cp++;
3367c478bdstevel@tonic-gate			if (! isdigit(c))
3377c478bdstevel@tonic-gate				return (-1);
3387c478bdstevel@tonic-gate			n *= 10;
3397c478bdstevel@tonic-gate			n += c - '0';
3407c478bdstevel@tonic-gate			/* Get seperator char */
3417c478bdstevel@tonic-gate			if (cp == ep)
3427c478bdstevel@tonic-gate				return (-1);
3437c478bdstevel@tonic-gate			c = *cp;
3447c478bdstevel@tonic-gate			if (c != ' ')
3457c478bdstevel@tonic-gate				return (-1);
3467c478bdstevel@tonic-gate			cp++;
3477c478bdstevel@tonic-gate		} else {
3487c478bdstevel@tonic-gate			/*
3497c478bdstevel@tonic-gate			 * Case 2, 2 digit year and as this is a so-called
3507c478bdstevel@tonic-gate			 * Unix date format and the begining of time was
3517c478bdstevel@tonic-gate			 * 1970 so we can extend this obsoleted date syntax
3527c478bdstevel@tonic-gate			 * past the year 1999 into the year 2038 for 32 bit
3537c478bdstevel@tonic-gate			 * machines and through 2069 for 64 bit machines.
3547c478bdstevel@tonic-gate			 */
3557c478bdstevel@tonic-gate			if (n > 69)
3567c478bdstevel@tonic-gate				n += 1900;
3577c478bdstevel@tonic-gate			else
3587c478bdstevel@tonic-gate				n += 2000;
3597c478bdstevel@tonic-gate		}
3607c478bdstevel@tonic-gate		year = n;
3617c478bdstevel@tonic-gate		/* Get GMT time */
3627c478bdstevel@tonic-gate		if (c != ' ')
3637c478bdstevel@tonic-gate			return (-1);
3647c478bdstevel@tonic-gate		if (cp == ep)
3657c478bdstevel@tonic-gate			return (-1);
3667c478bdstevel@tonic-gate		c = *cp++;
3677c478bdstevel@tonic-gate		if (! isdigit(c))
3687c478bdstevel@tonic-gate			return (-1);
3697c478bdstevel@tonic-gate		n = c - '0';
3707c478bdstevel@tonic-gate		if (cp == ep)
3717c478bdstevel@tonic-gate			return (-1);
3727c478bdstevel@tonic-gate		c = *cp++;
3737c478bdstevel@tonic-gate		if (! isdigit(c))
3747c478bdstevel@tonic-gate			return (-1);
3757c478bdstevel@tonic-gate		n *= 10;
3767c478bdstevel@tonic-gate		n += c - '0';
3777c478bdstevel@tonic-gate		hour = n;
3787c478bdstevel@tonic-gate		if (cp == ep)
3797c478bdstevel@tonic-gate			return (-1);
3807c478bdstevel@tonic-gate		c = *cp++;
3817c478bdstevel@tonic-gate		if (c != ':')
3827c478bdstevel@tonic-gate			return (-1);
3837c478bdstevel@tonic-gate		if (cp == ep)
3847c478bdstevel@tonic-gate			return (-1);
3857c478bdstevel@tonic-gate		c = *cp++;
3867c478bdstevel@tonic-gate		if (! isdigit(c))
3877c478bdstevel@tonic-gate			return (-1);
3887c478bdstevel@tonic-gate		n = c - '0';
3897c478bdstevel@tonic-gate		if (cp == ep)
3907c478bdstevel@tonic-gate			return (-1);
3917c478bdstevel@tonic-gate		c = *cp++;
3927c478bdstevel@tonic-gate		if (! isdigit(c))
3937c478bdstevel@tonic-gate			return (-1);
3947c478bdstevel@tonic-gate		n *= 10;
3957c478bdstevel@tonic-gate		n += c - '0';
3967c478bdstevel@tonic-gate		min = n;
3977c478bdstevel@tonic-gate		if (cp == ep)
3987c478bdstevel@tonic-gate			return (-1);
3997c478bdstevel@tonic-gate		c = *cp++;
4007c478bdstevel@tonic-gate		if (c != ':')
4017c478bdstevel@tonic-gate			return (-1);
4027c478bdstevel@tonic-gate		if (cp == ep)
4037c478bdstevel@tonic-gate			return (-1);
4047c478bdstevel@tonic-gate		c = *cp++;
4057c478bdstevel@tonic-gate		if (! isdigit(c))
4067c478bdstevel@tonic-gate			return (-1);
4077c478bdstevel@tonic-gate		n = c - '0';
4087c478bdstevel@tonic-gate		if (cp == ep)
4097c478bdstevel@tonic-gate			return (-1);
4107c478bdstevel@tonic-gate		c = *cp++;
4117c478bdstevel@tonic-gate		if (! isdigit(c))
4127c478bdstevel@tonic-gate			return (-1);
4137c478bdstevel@tonic-gate		n *= 10;
4147c478bdstevel@tonic-gate		n += c - '0';
4157c478bdstevel@tonic-gate		sec = n;
4167c478bdstevel@tonic-gate		if (cp == ep)
4177c478bdstevel@tonic-gate			return (-1);
4187c478bdstevel@tonic-gate		c = *cp++;
4197c478bdstevel@tonic-gate		if (c != ' ')
4207c478bdstevel@tonic-gate			return (-1);
4217c478bdstevel@tonic-gate		if (cp == ep)
4227c478bdstevel@tonic-gate			return (-1);
4237c478bdstevel@tonic-gate		c = *cp++;
4247c478bdstevel@tonic-gate		if (c != 'G')
4257c478bdstevel@tonic-gate			return (-1);
4267c478bdstevel@tonic-gate		if (cp == ep)
4277c478bdstevel@tonic-gate			return (-1);
4287c478bdstevel@tonic-gate		c = *cp++;
4297c478bdstevel@tonic-gate		if (c != 'M')
4307c478bdstevel@tonic-gate			return (-1);
4317c478bdstevel@tonic-gate		if (cp == ep)
4327c478bdstevel@tonic-gate			return (-1);
4337c478bdstevel@tonic-gate		c = *cp++;
4347c478bdstevel@tonic-gate		if (c != 'T')
4357c478bdstevel@tonic-gate			return (-1);
4367c478bdstevel@tonic-gate	} else {
4377c478bdstevel@tonic-gate		/* case 3, parse month */
4387c478bdstevel@tonic-gate		sc = c;
4397c478bdstevel@tonic-gate		tpp = months;
4407c478bdstevel@tonic-gate		tp = *tpp++;
4417c478bdstevel@tonic-gate		scp = cp;
4427c478bdstevel@tonic-gate		n = 0;
4437c478bdstevel@tonic-gate		while (cp < ep) {
4447c478bdstevel@tonic-gate			c = *cp;
4457c478bdstevel@tonic-gate			if (c == sc) {
4467c478bdstevel@tonic-gate				cp++;
4477c478bdstevel@tonic-gate				break;
4487c478bdstevel@tonic-gate			}
4497c478bdstevel@tonic-gate			c = tolower(c);
4507c478bdstevel@tonic-gate			if (*tp == 0 || tolower(*tp) != c) {
4517c478bdstevel@tonic-gate				if ((tp = *tpp++) == NULL)
4527c478bdstevel@tonic-gate					break;
4537c478bdstevel@tonic-gate				cp = scp;
4547c478bdstevel@tonic-gate				n++;
4557c478bdstevel@tonic-gate				continue;
4567c478bdstevel@tonic-gate			}
4577c478bdstevel@tonic-gate			cp++;
4587c478bdstevel@tonic-gate			tp++;
4597c478bdstevel@tonic-gate		}
4607c478bdstevel@tonic-gate		if (cp == NULL)
4617c478bdstevel@tonic-gate			return (-1);
4627c478bdstevel@tonic-gate		month = n;
4637c478bdstevel@tonic-gate		/* Get day of the month */
4647c478bdstevel@tonic-gate		if (cp == ep)
4657c478bdstevel@tonic-gate			return (-1);
4667c478bdstevel@tonic-gate		c = *cp++;
4677c478bdstevel@tonic-gate		if (! isdigit(c))
4687c478bdstevel@tonic-gate			return (-1);
4697c478bdstevel@tonic-gate		n = c - '0';
4707c478bdstevel@tonic-gate		if (cp == ep)
4717c478bdstevel@tonic-gate			return (-1);
4727c478bdstevel@tonic-gate		c = *cp++;
4737c478bdstevel@tonic-gate		if (! isdigit(c))
4747c478bdstevel@tonic-gate			return (-1);
4757c478bdstevel@tonic-gate		n *= 10;
4767c478bdstevel@tonic-gate		n += c - '0';
4777c478bdstevel@tonic-gate		day = n;
4787c478bdstevel@tonic-gate		/* Skip <SP> */
4797c478bdstevel@tonic-gate		if (cp == ep)
4807c478bdstevel@tonic-gate			return (-1);
4817c478bdstevel@tonic-gate		c = *cp++;
4827c478bdstevel@tonic-gate		if (c != ' ')
4837c478bdstevel@tonic-gate			return (-1);
4847c478bdstevel@tonic-gate		/* Get time */
4857c478bdstevel@tonic-gate		if (cp == ep)
4867c478bdstevel@tonic-gate			return (-1);
4877c478bdstevel@tonic-gate		c = *cp++;
4887c478bdstevel@tonic-gate		if (! isdigit(c))
4897c478bdstevel@tonic-gate			return (-1);
4907c478bdstevel@tonic-gate		n = c - '0';
4917c478bdstevel@tonic-gate		if (cp == ep)
4927c478bdstevel@tonic-gate			return (-1);
4937c478bdstevel@tonic-gate		c = *cp++;
4947c478bdstevel@tonic-gate		if (! isdigit(c))
4957c478bdstevel@tonic-gate			return (-1);
4967c478bdstevel@tonic-gate		n *= 10;
4977c478bdstevel@tonic-gate		n += c - '0';
4987c478bdstevel@tonic-gate		hour = n;
4997c478bdstevel@tonic-gate		if (cp == ep)
5007c478bdstevel@tonic-gate			return (-1);
5017c478bdstevel@tonic-gate		c = *cp++;
5027c478bdstevel@tonic-gate		if (c != ':')
5037c478bdstevel@tonic-gate			return (-1);
5047c478bdstevel@tonic-gate		if (cp == ep)
5057c478bdstevel@tonic-gate			return (-1);
5067c478bdstevel@tonic-gate		c = *cp++;
5077c478bdstevel@tonic-gate		if (! isdigit(c))
5087c478bdstevel@tonic-gate			return (-1);
5097c478bdstevel@tonic-gate		n = c - '0';
5107c478bdstevel@tonic-gate		if (cp == ep)
5117c478bdstevel@tonic-gate			return (-1);
5127c478bdstevel@tonic-gate		c = *cp++;
5137c478bdstevel@tonic-gate		if (! isdigit(c))
5147c478bdstevel@tonic-gate			return (-1);
5157c478bdstevel@tonic-gate		n *= 10;
5167c478bdstevel@tonic-gate		n += c - '0';
5177c478bdstevel@tonic-gate		min = n;
5187c478bdstevel@tonic-gate		if (cp == ep)
5197c478bdstevel@tonic-gate			return (-1);
5207c478bdstevel@tonic-gate		c = *cp++;
5217c478bdstevel@tonic-gate		if (c != ':')
5227c478bdstevel@tonic-gate			return (-1);
5237c478bdstevel@tonic-gate		if (cp == ep)
5247c478bdstevel@tonic-gate			return (-1);
5257c478bdstevel@tonic-gate		c = *cp++;
5267c478bdstevel@tonic-gate		if (! isdigit(c))
5277c478bdstevel@tonic-gate			return (-1);
5287c478bdstevel@tonic-gate		n = c - '0';
5297c478bdstevel@tonic-gate		if (cp == ep)
5307c478bdstevel@tonic-gate			return (-1);
5317c478bdstevel@tonic-gate		c = *cp++;
5327c478bdstevel@tonic-gate		if (! isdigit(c))
5337c478bdstevel@tonic-gate			return (-1);
5347c478bdstevel@tonic-gate		n *= 10;
5357c478bdstevel@tonic-gate		n += c - '0';
5367c478bdstevel@tonic-gate		sec = n;
5377c478bdstevel@tonic-gate		/* Skip <SP> */
5387c478bdstevel@tonic-gate		if (cp == ep)
5397c478bdstevel@tonic-gate			return (-1);
5407c478bdstevel@tonic-gate		c = *cp++;
5417c478bdstevel@tonic-gate		if (c != ' ')
5427c478bdstevel@tonic-gate			return (-1);
5437c478bdstevel@tonic-gate		/* Get year */
5447c478bdstevel@tonic-gate		if (cp == ep)
5457c478bdstevel@tonic-gate			return (-1);
5467c478bdstevel@tonic-gate		c = *cp++;
5477c478bdstevel@tonic-gate		if (! isdigit(c))
5487c478bdstevel@tonic-gate			return (-1);
5497c478bdstevel@tonic-gate		n = c - '0';
5507c478bdstevel@tonic-gate		if (cp == ep)
5517c478bdstevel@tonic-gate			return (-1);
5527c478bdstevel@tonic-gate		c = *cp++;
5537c478bdstevel@tonic-gate		if (! isdigit(c))
5547c478bdstevel@tonic-gate			return (-1);
5557c478bdstevel@tonic-gate		n *= 10;
5567c478bdstevel@tonic-gate		n += c - '0';
5577c478bdstevel@tonic-gate		if (cp == ep)
5587c478bdstevel@tonic-gate			return (-1);
5597c478bdstevel@tonic-gate		c = *cp++;
5607c478bdstevel@tonic-gate		if (! isdigit(c))
5617c478bdstevel@tonic-gate			return (-1);
5627c478bdstevel@tonic-gate		n *= 10;
5637c478bdstevel@tonic-gate		n += c - '0';
5647c478bdstevel@tonic-gate		if (cp == ep)
5657c478bdstevel@tonic-gate			return (-1);
5667c478bdstevel@tonic-gate		c = *cp++;
5677c478bdstevel@tonic-gate		if (! isdigit(c))
5687c478bdstevel@tonic-gate			return (-1);
5697c478bdstevel@tonic-gate		n *= 10;
5707c478bdstevel@tonic-gate		n += c - '0';
5717c478bdstevel@tonic-gate		year = n;
5727c478bdstevel@tonic-gate	}
5737c478bdstevel@tonic-gate
5747c478bdstevel@tonic-gate	/* Last, caclulate seconds since Unix day zero */
5757c478bdstevel@tonic-gate	leap = year;
5767c478bdstevel@tonic-gate	if (month < 2)
5777c478bdstevel@tonic-gate		leap--;
5787c478bdstevel@tonic-gate	leap = leap / 4 - leap / 100 + leap / 400 - zeroleap;
5797c478bdstevel@tonic-gate	secs = ((((year - 1970) * 365 + dom[month] + day  - 1 + leap) * 24
5800f1702cYu Xiangning<Eric.Yu@Sun.COM>	    + hour) * 60 + min) * 60 + sec;
5817c478bdstevel@tonic-gate
5827c478bdstevel@tonic-gate	return (secs);
5837c478bdstevel@tonic-gate}
5847c478bdstevel@tonic-gate
5857c478bdstevel@tonic-gate/*
5862c9e429brutus * http_today(char *) - returns in the given char* pointer the current
5872c9e429brutus * date in ascii with a format of (char [29]):
5882c9e429brutus *
5892c9e429brutus *	Sun, 07 Dec 1998 14:49:37 GMT	; RFC 822, updated by RFC 1123
5902c9e429brutus */
5912c9e429brutus
5922c9e429brutusstatic void
5932c9e429brutushttp_today(char *cp)
5942c9e429brutus{
5952c9e429brutus	ssize_t	i;
5962c9e429brutus	char	*fp;
5972c9e429brutus
5982c9e429brutus	ssize_t	leap;
5992c9e429brutus	ssize_t	year;
6002c9e429brutus	ssize_t	month;
6012c9e429brutus	ssize_t	dow;
6022c9e429brutus	ssize_t	day;
6032c9e429brutus	ssize_t	hour;
6042c9e429brutus	ssize_t	min;
6052c9e429brutus	ssize_t	sec;
6062c9e429brutus
6072c9e429brutus	/* Secs since Thu, 01 Jan 1970 00:00:00 GMT */
6082c9e429brutus	time_t	now = gethrestime_sec();
6092c9e429brutus
6102c9e429brutus	sec = now % 60;
6112c9e429brutus	now /= 60;
6122c9e429brutus	min = now % 60;
6132c9e429brutus	now /= 60;
6142c9e429brutus	hour = now % 24;
6152c9e429brutus	now /= 24;
6162c9e429brutus	dow = now % 7;
6172c9e429brutus
6182c9e429brutus	year = 1970;
6192c9e429brutus	for (;;) {
6202c9e429brutus		if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0)
6212c9e429brutus			day = 366;
6222c9e429brutus		else
6232c9e429brutus			day = 365;
6242c9e429brutus		if (now < day)
6252c9e429brutus			break;
6262c9e429brutus		now -= day;
6272c9e429brutus		year++;
6282c9e429brutus	}
6292c9e429brutus
6302c9e429brutus	now++;
6312c9e429brutus	if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0)
6322c9e429brutus		leap = 1;
6332c9e429brutus	else
6342c9e429brutus		leap = 0;
6352c9e429brutus	month = 11;
6362c9e429brutus	for (i = 11; i; i--) {
6372c9e429brutus		if (i < 2)
6382c9e429brutus			leap = 0;
6392c9e429brutus		if (now > dom[i] + leap)
6402c9e429brutus			break;
6412c9e429brutus		month--;
6422c9e429brutus	}
6432c9e429brutus	day = now - dom[i] - leap;
6442c9e429brutus
6452c9e429brutus	fp = Dow[dow];
6462c9e429brutus	*cp++ = *fp++;
6472c9e429brutus	*cp++ = *fp++;
6482c9e429brutus	*cp++ = *fp++;
6492c9e429brutus	*cp++ = ',';
6502c9e429brutus	*cp++ = ' ';
6512c9e429brutus
6522c9e429brutus	i = day / 10;
6532c9e429brutus	*cp++ = '0' + i;
6542c9e429brutus	*cp++ = '0' + (day - i * 10);
6552c9e429brutus	*cp++ = ' ';
6562c9e429brutus
6572c9e429brutus	fp = months[month];
6582c9e429brutus	*cp++ = *fp++;
6592c9e429brutus	*cp++ = *fp++;
6602c9e429brutus	*cp++ = *fp++;
6612c9e429brutus	*cp++ = ' ';
6622c9e429brutus
6632c9e429brutus	i = year / 1000;
6642c9e429brutus	*cp++ = '0' + i;
6652c9e429brutus	year -= i * 1000;
6662c9e429brutus	i = year / 100;
6672c9e429brutus	*cp++ = '0' + i;
6682c9e429brutus	year -= i * 100;
6692c9e429brutus	i = year / 10;
6702c9e429brutus	*cp++ = '0' + i;
6712c9e429brutus	year -= i * 10;
6722c9e429brutus	*cp++ = '0' + year;
6732c9e429brutus	*cp++ = ' ';
6742c9e429brutus
6752c9e429brutus	i = hour / 10;
6762c9e429brutus	*cp++ = '0' + i;
6772c9e429brutus	*cp++ = '0' + (hour - i * 10);
6782c9e429brutus	*cp++ = ':';
6792c9e429brutus
6802c9e429brutus	i = min / 10;
6812c9e429brutus	*cp++ = '0' + i;
6822c9e429brutus	*cp++ = '0' + (min - i * 10);
6832c9e429brutus	*cp++ = ':';
6842c9e429brutus
6852c9e429brutus	i = sec / 10;
6862c9e429brutus	*cp++ = '0' + i;
6872c9e429brutus	*cp++ = '0' + (sec - i * 10);
6882c9e429brutus	*cp++ = ' ';
6892c9e429brutus
6902c9e429brutus	*cp++ = 'G';
6912c9e429brutus	*cp++ = 'M';
6922c9e429brutus	*cp = 'T';
6932c9e429brutus}
6942c9e429brutus
6952c9e429brutus/*
6967c478bdstevel@tonic-gate * Given the ttree_t pointer "*t", parse the char buffer pointed to
6977c478bdstevel@tonic-gate * by "**cpp" of multiline text data up to the pointer "**epp", the
6987c478bdstevel@tonic-gate * pointer "*hash" points to the current text hash.
6997c478bdstevel@tonic-gate *
7007c478bdstevel@tonic-gate * If a match is found a pointer to the ttree_t token will be returned,
7017c478bdstevel@tonic-gate * "**cpp" will point to the next line, "**epp" will point to the first
7027c478bdstevel@tonic-gate * EOL char, "**hpp" will point to remainder of the parse data (if none,
7037c478bdstevel@tonic-gate * **hpp == **epp), and "*hash" will be updated.
7047c478bdstevel@tonic-gate *
7057c478bdstevel@tonic-gate * If no match, as above except "**hpp" points to the begining of the
7067c478bdstevel@tonic-gate * line and "*hash" wont be updated.
7077c478bdstevel@tonic-gate *
7087c478bdstevel@tonic-gate * If no EOL is found NULL is returned, "**epp" is set to NULL, no further
7097c478bdstevel@tonic-gate * calls can be made until additional data is ready and all arguments are
7107c478bdstevel@tonic-gate * reset.
7117c478bdstevel@tonic-gate *
7127c478bdstevel@tonic-gate * If EOH (i.e. an empty line) NULL is returned, "**hpp" is set to NULL,
7137c478bdstevel@tonic-gate * *cpp points to past EOH, no further calls can be made.
7147c478bdstevel@tonic-gate */
7157c478bdstevel@tonic-gate
7167c478bdstevel@tonic-gatestatic token_t *
7172c9e429brutusttree_line_parse(ttree_t *t, char **cpp, char **epp, char **hpp, uint32_t *hash)
7187c478bdstevel@tonic-gate{
7197c478bdstevel@tonic-gate	char	ca, cb;			/* current line <=> parse node */
7207c478bdstevel@tonic-gate
7217c478bdstevel@tonic-gate	char	*cp = *cpp;
7227c478bdstevel@tonic-gate	char	*ep = *epp;
7237c478bdstevel@tonic-gate
7247c478bdstevel@tonic-gate	char	*tp = t->tok->text;	/* current parse text */
7257c478bdstevel@tonic-gate	char	*sp = cp;		/* saved *cp */
7267c478bdstevel@tonic-gate
7277c478bdstevel@tonic-gate	int	parse;			/* parse state */
7287c478bdstevel@tonic-gate
7292c9e429brutus	uint32_t hv;			/* hash value */
7302c9e429brutus
7312c9e429brutus	if (hash != NULL)
7322c9e429brutus		hv = *hash;
7332c9e429brutus
7347c478bdstevel@tonic-gate	/* Special case, check for EOH (i.e. empty line) */
7357c478bdstevel@tonic-gate	if (cp < ep) {
7367c478bdstevel@tonic-gate		ca = *cp;
7377c478bdstevel@tonic-gate		if (ca == '\n') {
7387c478bdstevel@tonic-gate			/* End of header */
7397c478bdstevel@tonic-gate			*cpp = ++cp;
7407c478bdstevel@tonic-gate			*hpp = NULL;
7417c478bdstevel@tonic-gate			return (NULL);
7427c478bdstevel@tonic-gate		} else if (ca == '\r') {
7437c478bdstevel@tonic-gate			cp++;
7447c478bdstevel@tonic-gate			if (cp < ep) {
7457c478bdstevel@tonic-gate				ca = *cp;
7467c478bdstevel@tonic-gate				if (ca == '\n') {
7477c478bdstevel@tonic-gate					/* End of header */
7487c478bdstevel@tonic-gate					*cpp = ++cp;
7497c478bdstevel@tonic-gate					*hpp = NULL;
7507c478bdstevel@tonic-gate					return (NULL);
7517c478bdstevel@tonic-gate				}
7527c478bdstevel@tonic-gate			}
7537c478bdstevel@tonic-gate			cp = *cpp;
7547c478bdstevel@tonic-gate		}
7557c478bdstevel@tonic-gate	}
7567c478bdstevel@tonic-gate	while (cp < ep) {
7577c478bdstevel@tonic-gate		/* Get next parse text char */
7587c478bdstevel@tonic-gate		cb = *tp;
7597c478bdstevel@tonic-gate		if (cb != 0) {
7607c478bdstevel@tonic-gate			/* Get next current line char */
7617c478bdstevel@tonic-gate			ca = *cp++;
7622c9e429brutus			/* Case insensitive */
7632c9e429brutus			cb = tolower(cb);
7642c9e429brutus			ca = tolower(ca);
7652c9e429brutus			if (ca == cb) {
7662c9e429brutus				/*
7672c9e429brutus				 * Char match, next char.
7682c9e429brutus				 *
7692c9e429brutus				 * Note, parse text can contain EOL chars.
7702c9e429brutus				 */
7712c9e429brutus				tp++;
7722c9e429brutus				continue;
7732c9e429brutus			}
7747c478bdstevel@tonic-gate			if (ca == '\r' || ca == '\n') {
7757c478bdstevel@tonic-gate				/* EOL, always go less than */
7767c478bdstevel@tonic-gate				t = t->lt;
7772c9e429brutus			} else if (ca < cb) {
7782c9e429brutus				/* Go less than */
7792c9e429brutus				t = t->lt;
7807c478bdstevel@tonic-gate			} else {
7812c9e429brutus				/* Go greater than */
7822c9e429brutus				t = t->gt;
7837c478bdstevel@tonic-gate			}
7847c478bdstevel@tonic-gate			while (t != NULL && t->tok == NULL) {
7857c478bdstevel@tonic-gate				/* Null node, so descend to < node */
7867c478bdstevel@tonic-gate				t = t->lt;
7877c478bdstevel@tonic-gate			}
7887c478bdstevel@tonic-gate			if (t != NULL) {
7897c478bdstevel@tonic-gate				/* Initialize for next node compare */
7907c478bdstevel@tonic-gate				tp = t->tok->text;
7917c478bdstevel@tonic-gate				cp = sp;
7927c478bdstevel@tonic-gate				continue;
7937c478bdstevel@tonic-gate			}
7947c478bdstevel@tonic-gate			/*
7957c478bdstevel@tonic-gate			 * End of tree walk, no match, return pointer
7967c478bdstevel@tonic-gate			 * to the start of line then below find EOL.
7977c478bdstevel@tonic-gate			 */
7987c478bdstevel@tonic-gate			*hpp = *cpp;
7997c478bdstevel@tonic-gate		} else {
8007c478bdstevel@tonic-gate			/*
8017c478bdstevel@tonic-gate			 * End of token text, match, return pointer to
8027c478bdstevel@tonic-gate			 * the rest of header text then below find EOL.
8037c478bdstevel@tonic-gate			 */
8047c478bdstevel@tonic-gate			*hpp = cp;
8057c478bdstevel@tonic-gate		}
8067c478bdstevel@tonic-gate		/*
8077c478bdstevel@tonic-gate		 * Find end of line. Note, the HTTP line syntax supports
8087c478bdstevel@tonic-gate		 * implicit multi-line if the next line starts with a <SP>
8097c478bdstevel@tonic-gate		 * or <HT>.
8107c478bdstevel@tonic-gate		 */
8117c478bdstevel@tonic-gate		parse = 0;
8127c478bdstevel@tonic-gate		while (cp < ep) {
8137c478bdstevel@tonic-gate			ca = *cp;
8147c478bdstevel@tonic-gate			if (parse == 0 && ca == '\r') {
8157c478bdstevel@tonic-gate				*epp = cp;
8167c478bdstevel@tonic-gate				parse = 1;
8177c478bdstevel@tonic-gate			} else if (parse == 0 && ca == '\n') {
8187c478bdstevel@tonic-gate				*epp = cp;
8197c478bdstevel@tonic-gate				parse = 2;
8207c478bdstevel@tonic-gate			} else if (parse == 1 && ca == '\n') {
8217c478bdstevel@tonic-gate				parse = 2;
8227c478bdstevel@tonic-gate			} else if (parse >= 2 && (ca == ' ' || ca == '\t')) {
8237c478bdstevel@tonic-gate				parse++;
8247c478bdstevel@tonic-gate			} else if (parse > 2) {
8257c478bdstevel@tonic-gate				parse = 0;
8267c478bdstevel@tonic-gate			} else if (parse == 2) {
8277c478bdstevel@tonic-gate				break;
8282c9e429brutus			} else if (t != NULL && (t->tok->act & HASH) &&
8292c9e429brutus			    hash != NULL) {
8302c9e429brutus				CHASH(hv, ca);
8317c478bdstevel@tonic-gate			}
8327c478bdstevel@tonic-gate			cp++;
8337c478bdstevel@tonic-gate		}
8347c478bdstevel@tonic-gate		if (parse < 2) {
8357c478bdstevel@tonic-gate			/* No EOL, not enough data */
8367c478bdstevel@tonic-gate			*epp = NULL;
8377c478bdstevel@tonic-gate			return (t != NULL ? t->tok : NULL);
8387c478bdstevel@tonic-gate		}
8397c478bdstevel@tonic-gate		/*
8407c478bdstevel@tonic-gate		 * Return updated hash value (if any), update parse current
8417c478bdstevel@tonic-gate		 * pointer for next call (i.e. begin of next line), and last
8427c478bdstevel@tonic-gate		 * return pointer to the matching token_t.
8437c478bdstevel@tonic-gate		 */
8442c9e429brutus		if (t != NULL && (t->tok->act & HASH) && hash != NULL)
8457c478bdstevel@tonic-gate			*hash = hv;
8467c478bdstevel@tonic-gate		*cpp = cp;
8477c478bdstevel@tonic-gate		return (t != NULL ? t->tok : NULL);
8487c478bdstevel@tonic-gate	}
8497c478bdstevel@tonic-gate	/*
8507c478bdstevel@tonic-gate	 * End of parse text, ...
8517c478bdstevel@tonic-gate	 */
8527c478bdstevel@tonic-gate	*epp = NULL;
8537c478bdstevel@tonic-gate	return (NULL);
8547c478bdstevel@tonic-gate}
8557c478bdstevel@tonic-gate
8567c478bdstevel@tonic-gate/*
8577c478bdstevel@tonic-gate * Given a NULL terminated array of token_t(s) ordered in ascending
8587c478bdstevel@tonic-gate * case insensitive order a binary tree is allocated and populated with
8597c478bdstevel@tonic-gate * pointers into the array and a pointer to the root node is returned.
8607c478bdstevel@tonic-gate *
8617c478bdstevel@tonic-gate * Todo, for maximum ttree parse efficiency needs to be path compressed,
8627c478bdstevel@tonic-gate * the function ttree_line_parse() handles the empty nodes correctly.
8637c478bdstevel@tonic-gate */
8647c478bdstevel@tonic-gatestatic ttree_t *
8657c478bdstevel@tonic-gatettree_build(token_t *list, int sz)
8667c478bdstevel@tonic-gate{
8677c478bdstevel@tonic-gate	ttree_t *treev;
8687c478bdstevel@tonic-gate	int	max, lvl, inc, ix;
8697c478bdstevel@tonic-gate
8707c478bdstevel@tonic-gate	/* calc the size of the tree */
8717c478bdstevel@tonic-gate	for (max = 1; max < sz; max <<= 1)
8727c478bdstevel@tonic-gate		;
8737c478bdstevel@tonic-gate	/* allocate the tree */
8747c478bdstevel@tonic-gate	treev = kmem_alloc(sizeof (*treev) * (max - 1), KM_SLEEP);
8757c478bdstevel@tonic-gate
8767c478bdstevel@tonic-gate	/* walk the tree and populate from list vector */
8777c478bdstevel@tonic-gate	lvl = max;
8787c478bdstevel@tonic-gate	while (lvl >>= 1) {
8797c478bdstevel@tonic-gate		inc = lvl >> 1;
8807c478bdstevel@tonic-gate		for (ix = lvl; ix < max; ix += lvl << 1) {
8817c478bdstevel@tonic-gate			if (ix <= sz) {
8827c478bdstevel@tonic-gate				treev[ix - 1].tok = &list[ix - 1];
8837c478bdstevel@tonic-gate			} else {
8847c478bdstevel@tonic-gate				treev[ix - 1].tok = 0;
8857c478bdstevel@tonic-gate			}
8867c478bdstevel@tonic-gate			if (inc) {
8877c478bdstevel@tonic-gate				treev[ix - 1].lt = &treev[ix - inc - 1];
8887c478bdstevel@tonic-gate				treev[ix - 1].gt = &treev[ix + inc - 1];
8897c478bdstevel@tonic-gate			} else {
8907c478bdstevel@tonic-gate				treev[ix - 1].lt = 0;
8917c478bdstevel@tonic-gate				treev[ix - 1].gt = 0;
8927c478bdstevel@tonic-gate			}
8937c478bdstevel@tonic-gate		}
8947c478bdstevel@tonic-gate	}
8957c478bdstevel@tonic-gate
8967c478bdstevel@tonic-gate	return (&treev[(max >> 1) - 1]);
8977c478bdstevel@tonic-gate}
8987c478bdstevel@tonic-gate
8997c478bdstevel@tonic-gatevoid
9007c478bdstevel@tonic-gatenl7c_http_init(void)
9017c478bdstevel@tonic-gate{
9027c478bdstevel@tonic-gate	int	n;
9037c478bdstevel@tonic-gate
9047c478bdstevel@tonic-gate	http_kmc = kmem_cache_create("NL7C_http_kmc",
9057c478bdstevel@tonic-gate	    sizeof (http_t), 0, NULL, NULL, NULL, NULL, NULL, 0);
9067c478bdstevel@tonic-gate
9077c478bdstevel@tonic-gate	req_tree = ttree_build(tokreq, tokreq_cnt - 1);
9087c478bdstevel@tonic-gate	res_tree = ttree_build(tokres, tokres_cnt - 1);
9097c478bdstevel@tonic-gate
9107c478bdstevel@tonic-gate	n = sizeof (Shttp_conn_cl) - 1;
9117c478bdstevel@tonic-gate	http_conn_cl = allocb_wait(n, BPRI_HI, STR_NOSIG, NULL);
9127c478bdstevel@tonic-gate	bcopy(Shttp_conn_cl, http_conn_cl->b_rptr, n);
9137c478bdstevel@tonic-gate	http_conn_cl->b_wptr += n;
9147c478bdstevel@tonic-gate
9157c478bdstevel@tonic-gate	n = sizeof (Shttp_conn_ka) - 1;
9167c478bdstevel@tonic-gate	http_conn_ka = allocb_wait(n, BPRI_HI, STR_NOSIG, NULL);
9177c478bdstevel@tonic-gate	bcopy(Shttp_conn_ka, http_conn_ka->b_rptr, n);
9187c478bdstevel@tonic-gate	http_conn_ka->b_wptr += n;
9197c478bdstevel@tonic-gate}
9207c478bdstevel@tonic-gate
9217c478bdstevel@tonic-gatevoid
9227c478bdstevel@tonic-gatenl7c_http_free(void *arg)
9237c478bdstevel@tonic-gate{
9247c478bdstevel@tonic-gate	http_t	*http = arg;
9257c478bdstevel@tonic-gate
9267c478bdstevel@tonic-gate	kmem_cache_free(http_kmc, http);
9277c478bdstevel@tonic-gate}
9287c478bdstevel@tonic-gate
9297c478bdstevel@tonic-gate#define	STR_T_NOTCMP_OPT(a, b, m) (					\
9307c478bdstevel@tonic-gate    a->m.cp && b->m.cp &&						\
9317c478bdstevel@tonic-gate	((a->m.ep - a->m.cp) != (b->m.ep - b->m.cp) ||			\
9327c478bdstevel@tonic-gate	strncmp(a->m.cp, b->m.cp, (b->m.ep - b->m.cp))))
9337c478bdstevel@tonic-gate
9347c478bdstevel@tonic-gate#define	STR_T_NOTCMP(a, b, m) (						\
9357c478bdstevel@tonic-gate    a->m.cp && ! b->m.cp ||						\
9367c478bdstevel@tonic-gate    b->m.cp && ! a->m.cp ||						\
9377c478bdstevel@tonic-gate    STR_T_NOTCMP_OPT(a, b, m))
9387c478bdstevel@tonic-gate
9397c478bdstevel@tonic-gateboolean_t
9407c478bdstevel@tonic-gatenl7c_http_cmp(void *arg1, void *arg2)
9417c478bdstevel@tonic-gate{
9427c478bdstevel@tonic-gate	http_t	*httpa = arg1;		/* Response */
9437c478bdstevel@tonic-gate	http_t	*httpb = arg2;		/* Request */
9447c478bdstevel@tonic-gate
9457c478bdstevel@tonic-gate	if (httpa->major != httpb->major ||
9467c478bdstevel@tonic-gate	    httpa->minor != httpb->minor ||
9477c478bdstevel@tonic-gate	    STR_T_NOTCMP(httpa, httpb, accept) ||
9487c478bdstevel@tonic-gate	    STR_T_NOTCMP(httpa, httpb, acceptchar) ||
9497c478bdstevel@tonic-gate	    STR_T_NOTCMP(httpa, httpb, acceptenco) ||
9507c478bdstevel@tonic-gate	    STR_T_NOTCMP(httpa, httpb, acceptlang) ||
9517c478bdstevel@tonic-gate	    STR_T_NOTCMP_OPT(httpa, httpb, etag))
9527c478bdstevel@tonic-gate		return (B_FALSE);
9537c478bdstevel@tonic-gate	return (B_TRUE);
9547c478bdstevel@tonic-gate}
9557c478bdstevel@tonic-gate
9567c478bdstevel@tonic-gate/*
9572c9e429brutus * In-line HTTP responses:
9582c9e429brutus */
9592c9e429brutus
9602c9e429brutusstatic char http_resp_304[] =
9612c9e429brutus	"HTTP/#.# 304 Not Modified\r\n"
9622c9e429brutus	"Date: #############################\r\n"
9632c9e429brutus	"Server: NCA/#.# (Solaris)\r\n";
9642c9e429brutus
9652c9e429brutusstatic char http_resp_412[] =
9662c9e429brutus	"HTTP/#.# 412 Precondition Failed\r\n"
9672c9e429brutus	"Date: #############################\r\n"
9682c9e429brutus	"Server: NCA/#.# (Solaris)\r\n";
9692c9e429brutus
9702c9e429brutusstatic uri_desc_t *
9712c9e429brutushttp_mkresponse(uri_desc_t *req, uri_desc_t *res, char *proto, int sz)
9722c9e429brutus{
9732c9e429brutus	http_t		*qhttp = req->scheme;
9742c9e429brutus	http_t		*shttp = res->scheme;
9752c9e429brutus	uri_desc_t	*uri = kmem_cache_alloc(nl7c_uri_kmc, KM_SLEEP);
9762c9e429brutus	char		*alloc;
9772c9e429brutus	char		*cp;
9782c9e429brutus	char		*ep = &proto[sz];
9792c9e429brutus	uri_rd_t	*rdp;
9802c9e429brutus	int		cnt;
9812c9e429brutus
9822c9e429brutus	char		hdr_etag[] = "ETag: ";
9832c9e429brutus
9842c9e429brutus	/* Any optional header(s) */
9852c9e429brutus	if (shttp->etag.cp != NULL) {
9862c9e429brutus		/* Response has an ETag:, count it */
9872c9e429brutus		sz += sizeof (hdr_etag) - 1 +
9882c9e429brutus		    (shttp->etag.ep - shttp->etag.cp) + 2;
9892c9e429brutus	}
9902c9e429brutus	sz += 2;
9912c9e429brutus	alloc = kmem_alloc(sz, KM_SLEEP);
9922c9e429brutus
9932c9e429brutus	/* Minimum temp uri initialization as needed by uri_response() */
9942c9e429brutus	REF_INIT(uri, 1, nl7c_uri_inactive, nl7c_uri_kmc);
9952c9e429brutus	uri->hash = URI_TEMP;
9962c9e429brutus	uri->tail = NULL;
9972c9e429brutus	uri->scheme = NULL;
9982c9e429brutus	uri->reqmp = NULL;
9992c9e429brutus	uri->count = 0;
10002c9e429brutus	cv_init(&uri->waiting, NULL, CV_DEFAULT, NULL);
10012c9e429brutus	mutex_init(&uri->proclock, NULL, MUTEX_DEFAULT, NULL);
10022c9e429brutus
10032c9e429brutus	URI_RD_ADD(uri, rdp, sz, -1);
10042c9e429brutus	rdp->data.kmem = alloc;
10052c9e429brutus	atomic_add_64(&nl7c_uri_bytes, sz);
10062c9e429brutus
10072c9e429brutus	cp = alloc;
10082c9e429brutus	if (qhttp->major == 1) {
10092c9e429brutus		/*
10102c9e429brutus		 * Full response format.
10112c9e429brutus		 *
10122c9e429brutus		 * Copy to first sub char '#'.
10132c9e429brutus		 */
10142c9e429brutus		while (proto < ep) {
10152c9e429brutus			if (*proto == '#')
10162c9e429brutus				break;
10172c9e429brutus			*cp++ = *proto++;
10182c9e429brutus		}
10192c9e429brutus
10202c9e429brutus		/* Process the HTTP version substitutions */
10212c9e429brutus		if (*proto != '#') goto bad;
10222c9e429brutus		*cp++ = '0' + qhttp->major;
10232c9e429brutus		proto++;
10242c9e429brutus		while (proto < ep) {
10252c9e429brutus			if (*proto == '#')
10262c9e429brutus				break;
10272c9e429brutus			*cp++ = *proto++;
10282c9e429brutus		}
10292c9e429brutus		if (*proto != '#') goto bad;
10302c9e429brutus		*cp++ = '0' + qhttp->minor;
10312c9e429brutus		proto++;
10322c9e429brutus
10332c9e429brutus		/* Copy to the next sub char '#' */
10342c9e429brutus		while (proto < ep) {
10352c9e429brutus			if (*proto == '#')
10362c9e429brutus				break;
10372c9e429brutus			*cp++ = *proto++;
10382c9e429brutus		}
10392c9e429brutus
10402c9e429brutus		/* Process the "Date: " substitution */
10412c9e429brutus		if (*proto != '#') goto bad;
10422c9e429brutus		http_today(cp);
10432c9e429brutus
10442c9e429brutus		/* Skip to the next nonsub char '#' */
10452c9e429brutus		while (proto < ep) {
10462c9e429brutus			if (*proto != '#')
10472c9e429brutus				break;
10482c9e429brutus			cp++;
10492c9e429brutus			proto++;
10502c9e429brutus		}
10512c9e429brutus
10522c9e429brutus		/* Copy to the next sub char '#' */
10532c9e429brutus		while (proto < ep) {
10542c9e429brutus			if (*proto == '#')
10552c9e429brutus				break;
10562c9e429brutus			*cp++ = *proto++;
10572c9e429brutus		}
10582c9e429brutus
10592c9e429brutus		/* Process the NCA version substitutions */
10602c9e429brutus		if (*proto != '#') goto bad;
10612c9e429brutus		*cp++ = '0' + nca_major_version;
10622c9e429brutus		proto++;
10632c9e429brutus		while (proto < ep) {
10642c9e429brutus			if (*proto == '#')
10652c9e429brutus				break;
10662c9e429brutus			*cp++ = *proto++;
10672c9e429brutus		}
10682c9e429brutus		if (*proto != '#') goto bad;
10692c9e429brutus		*cp++ = '0' + nca_minor_version;
10702c9e429brutus		proto++;
10712c9e429brutus
10722c9e429brutus		/* Copy remainder of HTTP header */
10732c9e429brutus		while (proto < ep) {
10742c9e429brutus			*cp++ = *proto++;
10752c9e429brutus		}
10762c9e429brutus	} else {
10772c9e429brutus		goto bad;
10782c9e429brutus	}
10792c9e429brutus	/* Any optional header(s) */
10802c9e429brutus	if (shttp->etag.cp != NULL) {
10812c9e429brutus		/* Response has an ETag:, add it */
10822c9e429brutus		cnt = sizeof (hdr_etag) - 1;
10832c9e429brutus		bcopy(hdr_etag, cp, cnt);
10842c9e429brutus		cp += cnt;
10852c9e429brutus		cnt = (shttp->etag.ep - shttp->etag.cp);
10862c9e429brutus		bcopy(shttp->etag.cp, cp, cnt);
10872c9e429brutus		cp += cnt;
10882c9e429brutus		*cp++ = '\r';
10892c9e429brutus		*cp++ = '\n';
10902c9e429brutus	}
10912c9e429brutus	/* Last, add empty line */
10922c9e429brutus	uri->eoh = cp;
10932c9e429brutus	*cp++ = '\r';
10942c9e429brutus	*cp = '\n';
10952c9e429brutus
10962c9e429brutus	return (uri);
10972c9e429brutus
10982c9e429brutusbad:
10992c9e429brutus	/*
11002c9e429brutus	 * Free any resources allocated here, note that while we could
11012c9e429brutus	 * use the uri_inactive() to free the uri by doing a REF_RELE()
11022c9e429brutus	 * we instead free it here as the URI may be in less then a fully
11032c9e429brutus	 * initialized state.
11042c9e429brutus	 */
11052c9e429brutus	kmem_free(alloc, sz);
11062c9e429brutus	kmem_cache_free(nl7c_uri_kmc, uri);
11072c9e429brutus	return (NULL);
11082c9e429brutus}
11092c9e429brutus
11102c9e429brutusuri_desc_t *
11112c9e429brutusnl7c_http_cond(uri_desc_t *req, uri_desc_t *res)
11122c9e429brutus{
11132c9e429brutus	http_t	*qhttp = req->scheme;
11142c9e429brutus	time_t	qdate = qhttp->moddate;
11152c9e429brutus	http_t	*shttp = res->scheme;
11162c9e429brutus	time_t	sdate = shttp->lastmod == -1 ? shttp->date : shttp->lastmod;
11172c9e429brutus	uri_desc_t *uri;
11182c9e429brutus
11192c9e429brutus	if (qhttp->modtokid == Qhdr_If_Modified_Since &&
11202c9e429brutus	    sdate != -1 && qdate != -1 && sdate <= qdate) {
11212c9e429brutus		/*
11222c9e429brutus		 * Request is If-Modified-Since: and both response
11232c9e429brutus		 * and request dates are valid and response is the
11242c9e429brutus		 * same age as request so return a 304 response uri
11252c9e429brutus		 * instead of the cached response.
11262c9e429brutus		 */
11272c9e429brutus		nl7c_http_cond_304++;
11282c9e429brutus		uri = http_mkresponse(req, res, http_resp_304,
11292c9e429brutus		    sizeof (http_resp_304) - 1);
11302c9e429brutus		if (uri != NULL) {
11312c9e429brutus			/* New response uri */
11322c9e429brutus			REF_RELE(res);
11332c9e429brutus			return (uri);
11342c9e429brutus		}
11352c9e429brutus		return (res);
11362c9e429brutus	} else if (qhttp->modtokid == Qhdr_If_Unmodified_Since &&
11372c9e429brutus	    sdate != -1 && qdate != -1 && sdate >= qdate) {
11382c9e429brutus		/*
11392c9e429brutus		 * Request is If-Unmodified-Since: and both response
11402c9e429brutus		 * and request dates are valid and response is not the
11412c9e429brutus		 * same age as the request so return a 412 response
11422c9e429brutus		 * uri instead of the cached response.
11432c9e429brutus		 */
11442c9e429brutus		nl7c_http_cond_412++;
11452c9e429brutus		uri = http_mkresponse(req, res, http_resp_412,
11462c9e429brutus		    sizeof (http_resp_412) - 1);
11472c9e429brutus		if (uri != NULL) {
11482c9e429brutus			/* New response uri */
11492c9e429brutus			REF_RELE(res);
11502c9e429brutus			return (uri);
11512c9e429brutus		}
11522c9e429brutus		return (res);
11532c9e429brutus	}
11542c9e429brutus	/*
11552c9e429brutus	 * No conditional response meet or unknown type or no
11562c9e429brutus	 * valid dates so just return the original uri response.
11572c9e429brutus	 */
11582c9e429brutus	return (res);
11592c9e429brutus}
11602c9e429brutus
11612c9e429brutus/*
11627c478bdstevel@tonic-gate * Return the appropriate HTTP connection persist header
11637c478bdstevel@tonic-gate * based on the request HTTP persistent header state.
11647c478bdstevel@tonic-gate */
11657c478bdstevel@tonic-gate
11667c478bdstevel@tonic-gatemblk_t *
11677c478bdstevel@tonic-gatenl7c_http_persist(struct sonode *so)
11687c478bdstevel@tonic-gate{
11690f1702cYu Xiangning<Eric.Yu@Sun.COM>	uint64_t	flags = SOTOTPI(so)->sti_nl7c_flags & NL7C_SCHEMEPRIV;
11707c478bdstevel@tonic-gate	mblk_t		*mp;
11717c478bdstevel@tonic-gate
11727c478bdstevel@tonic-gate	if (flags & HTTP_CONN_CL)
11737c478bdstevel@tonic-gate		mp = dupb(http_conn_cl);
11747c478bdstevel@tonic-gate	else if (flags & HTTP_CONN_KA)
11757c478bdstevel@tonic-gate		mp = dupb(http_conn_ka);
11767c478bdstevel@tonic-gate	else
11777c478bdstevel@tonic-gate		mp = NULL;
11787c478bdstevel@tonic-gate	return (mp);
11797c478bdstevel@tonic-gate}
11807c478bdstevel@tonic-gate
11817c478bdstevel@tonic-gate/*
11827c478bdstevel@tonic-gate * Parse the buffer *p of size len and update the uri_desc_t *uri and our
11837c478bdstevel@tonic-gate * http_t *http with the results.
11847c478bdstevel@tonic-gate */
11857c478bdstevel@tonic-gate
11867c478bdstevel@tonic-gateboolean_t
11877c478bdstevel@tonic-gatenl7c_http_request(char **cpp, char *ep, uri_desc_t *uri, struct sonode *so)
11887c478bdstevel@tonic-gate{
11890f1702cYu Xiangning<Eric.Yu@Sun.COM>	sotpi_info_t *sti = SOTOTPI(so);
11907c478bdstevel@tonic-gate	http_t	*http = kmem_cache_alloc(http_kmc, KM_SLEEP);
11917c478bdstevel@tonic-gate	char	*cp = *cpp;
11927c478bdstevel@tonic-gate	char	*hp;
11932c9e429brutus	char	*scp, *sep;
11947c478bdstevel@tonic-gate	char	*HTTP = "HTTP/";
11957c478bdstevel@tonic-gate	token_t	*match;
11967c478bdstevel@tonic-gate	boolean_t persist = B_FALSE;
11977c478bdstevel@tonic-gate
11987c478bdstevel@tonic-gate	ASSERT(cp <= ep);
11997c478bdstevel@tonic-gate
12007c478bdstevel@tonic-gate	if (cp == ep) {
12012c9e429brutus		goto bad;
12027c478bdstevel@tonic-gate	}
12037c478bdstevel@tonic-gate	/*
12047c478bdstevel@tonic-gate	 * Initialize any uri_desc_t and/or http_t members.
12057c478bdstevel@tonic-gate	 */
12067c478bdstevel@tonic-gate	uri->scheme = (void *)http;
12077c478bdstevel@tonic-gate	uri->auth.cp = NULL;
12087c478bdstevel@tonic-gate	uri->auth.ep = NULL;
12092c9e429brutus	uri->resplen = URI_LEN_NOVALUE;
12102c9e429brutus	uri->respclen = URI_LEN_NOVALUE;
12117c478bdstevel@tonic-gate	uri->eoh = NULL;
12127c478bdstevel@tonic-gate	uri->nocache = B_FALSE;
12132c9e429brutus	uri->conditional = B_FALSE;
12147c478bdstevel@tonic-gate	http->parsed = B_FALSE;
12157c478bdstevel@tonic-gate	http->accept.cp = NULL;
12167c478bdstevel@tonic-gate	http->acceptchar.cp = NULL;
12177c478bdstevel@tonic-gate	http->acceptenco.cp = NULL;
12187c478bdstevel@tonic-gate	http->acceptlang.cp = NULL;
12197c478bdstevel@tonic-gate	http->etag.cp = NULL;
12207c478bdstevel@tonic-gate	http->uagent.cp = NULL;
12217c478bdstevel@tonic-gate	http->date = -1;
12227c478bdstevel@tonic-gate	http->expire = -1;
12232c9e429brutus	http->lastmod = -1;
12247c478bdstevel@tonic-gate	if (*cp == '\r') {
12257c478bdstevel@tonic-gate		/*
12267c478bdstevel@tonic-gate		 * Special case for a Request-Line without an HTTP version,
12277c478bdstevel@tonic-gate		 * assume it's an old style, i.e. HTTP version 0.9 request.
12287c478bdstevel@tonic-gate		 */
12297c478bdstevel@tonic-gate		http->major = 0;
12307c478bdstevel@tonic-gate		http->minor = 9;
12317c478bdstevel@tonic-gate		goto got_version;
12327c478bdstevel@tonic-gate	}
12337c478bdstevel@tonic-gate	/*
12347c478bdstevel@tonic-gate	 * Skip URI path delimiter, must be a <SP>.
12357c478bdstevel@tonic-gate	 */
12367c478bdstevel@tonic-gate	if (*cp++ != ' ')
12377c478bdstevel@tonic-gate		/* Unkown or bad Request-Line format, just punt */
12382c9e429brutus		goto bad;
12397c478bdstevel@tonic-gate	/*
12407c478bdstevel@tonic-gate	 * The URI parser has parsed through the URI and the <SP>
12417c478bdstevel@tonic-gate	 * delimiter, parse the HTTP/N.N version
12427c478bdstevel@tonic-gate	 */
12437c478bdstevel@tonic-gate	while (cp < ep && *HTTP == *cp) {
12447c478bdstevel@tonic-gate		HTTP++;
12457c478bdstevel@tonic-gate		cp++;
12467c478bdstevel@tonic-gate	}
12477c478bdstevel@tonic-gate	if (*HTTP != 0) {
12487c478bdstevel@tonic-gate		if (cp == ep)
12497c478bdstevel@tonic-gate			goto more;
12502c9e429brutus		goto bad;
12517c478bdstevel@tonic-gate	}
12527c478bdstevel@tonic-gate	if (cp == ep)
12537c478bdstevel@tonic-gate		goto more;
12547c478bdstevel@tonic-gate	if (*cp < '0' || *cp > '9')
12552c9e429brutus		goto bad;
12567c478bdstevel@tonic-gate	http->major = *cp++ - '0';
12577c478bdstevel@tonic-gate	if (cp == ep)
12587c478bdstevel@tonic-gate		goto more;
12597c478bdstevel@tonic-gate	if (*cp++ != '.')
12602c9e429brutus		goto bad;
12617c478bdstevel@tonic-gate	if (cp == ep)
12627c478bdstevel@tonic-gate		goto more;
12637c478bdstevel@tonic-gate	if (*cp < '0' || *cp > '9')
12642c9e429brutus		goto bad;
12657c478bdstevel@tonic-gate	http->minor = *cp++ - '0';
12667c478bdstevel@tonic-gate	if (cp == ep)
12677c478bdstevel@tonic-gate		goto more;
12687c478bdstevel@tonic-gate
12697c478bdstevel@tonic-gategot_version:
12707c478bdstevel@tonic-gate
12717c478bdstevel@tonic-gate	if (*cp++ != '\r')
12722c9e429brutus		goto bad;
12737c478bdstevel@tonic-gate	if (cp == ep)
12747c478bdstevel@tonic-gate		goto more;
12757c478bdstevel@tonic-gate	if (*cp++ != '\n')
12762c9e429brutus		goto bad;
12777c478bdstevel@tonic-gate	/*
12787c478bdstevel@tonic-gate	 * Initialize persistent state based on HTTP version.
12797c478bdstevel@tonic-gate	 */
12807c478bdstevel@tonic-gate	if (http->major == 1) {
12817c478bdstevel@tonic-gate		if (http->minor >= 1) {
12827c478bdstevel@tonic-gate			/* 1.1 persistent by default */
12837c478bdstevel@tonic-gate			persist = B_TRUE;
12847c478bdstevel@tonic-gate		} else {
12857c478bdstevel@tonic-gate			/* 1.0 isn't persistent by default */
12867c478bdstevel@tonic-gate			persist = B_FALSE;
12877c478bdstevel@tonic-gate		}
12887c478bdstevel@tonic-gate	} else if (http->major == 0) {
12897c478bdstevel@tonic-gate		/* Before 1.0 no persistent connections */
12907c478bdstevel@tonic-gate		persist = B_FALSE;
12917c478bdstevel@tonic-gate	} else {
12927c478bdstevel@tonic-gate		/* >= 2.0 not supported (yet) */
12932c9e429brutus		goto bad;
12947c478bdstevel@tonic-gate	}
12957c478bdstevel@tonic-gate	/*
12967c478bdstevel@tonic-gate	 * Parse HTTP headers through the EOH
12977c478bdstevel@tonic-gate	 * (End Of Header, i.e. an empty line).
12987c478bdstevel@tonic-gate	 */
12997c478bdstevel@tonic-gate	for (sep = ep; cp < ep; ep = sep) {
13007c478bdstevel@tonic-gate		/* Get the next line */
13012c9e429brutus		scp = cp;
13022c9e429brutus		match = ttree_line_parse(req_tree, &cp, &ep, &hp, &uri->hvalue);
13037c478bdstevel@tonic-gate		if (match != NULL) {
13047c478bdstevel@tonic-gate			if (match->act & QUALIFIER) {
13057c478bdstevel@tonic-gate				/*
13067c478bdstevel@tonic-gate				 * Header field text is used to qualify this
13077c478bdstevel@tonic-gate				 * request/response, based on qualifier type
13087c478bdstevel@tonic-gate				 * optionally convert and store *http.
13097c478bdstevel@tonic-gate				 */
13107c478bdstevel@tonic-gate				char	c;
13117c478bdstevel@tonic-gate				int	n = 0;
13127c478bdstevel@tonic-gate				time_t	secs;
13137c478bdstevel@tonic-gate
13147c478bdstevel@tonic-gate				ASSERT(hp != NULL && ep != NULL);
13157c478bdstevel@tonic-gate
13167c478bdstevel@tonic-gate				if (match->act & NUMERIC) {
13177c478bdstevel@tonic-gate					while (hp < ep) {
13187c478bdstevel@tonic-gate						c = *hp++;
13197c478bdstevel@tonic-gate						if (! isdigit(c))
13202c9e429brutus							goto bad;
13217c478bdstevel@tonic-gate						n *= 10;
13227c478bdstevel@tonic-gate						n += c - '0';
13237c478bdstevel@tonic-gate					}
13247c478bdstevel@tonic-gate				} else if (match->act & DATE) {
13257c478bdstevel@tonic-gate					secs = http_date2time_t(hp, ep);
13267c478bdstevel@tonic-gate				}
13277c478bdstevel@tonic-gate				switch (match->tokid) {
13287c478bdstevel@tonic-gate
13297c478bdstevel@tonic-gate				case Qhdr_Accept_Charset:
13307c478bdstevel@tonic-gate					http->acceptchar.cp = hp;
13317c478bdstevel@tonic-gate					http->acceptchar.ep = ep;
13327c478bdstevel@tonic-gate					break;
13337c478bdstevel@tonic-gate
13347c478bdstevel@tonic-gate				case Qhdr_Accept_Encoding:
13357c478bdstevel@tonic-gate					http->acceptenco.cp = hp;
13367c478bdstevel@tonic-gate					http->acceptenco.ep = ep;
13377c478bdstevel@tonic-gate					break;
13387c478bdstevel@tonic-gate
13397c478bdstevel@tonic-gate				case Qhdr_Accept_Language:
13407c478bdstevel@tonic-gate					http->acceptlang.cp = hp;
13417c478bdstevel@tonic-gate					http->acceptlang.ep = ep;
13427c478bdstevel@tonic-gate					break;
13437c478bdstevel@tonic-gate
13447c478bdstevel@tonic-gate				case Qhdr_Accept:
13457c478bdstevel@tonic-gate					http->accept.cp = hp;
13467c478bdstevel@tonic-gate					http->accept.ep = ep;
13477c478bdstevel@tonic-gate					break;
13487c478bdstevel@tonic-gate
13497c478bdstevel@tonic-gate				case Qhdr_Authorization:
13507c478bdstevel@tonic-gate					goto pass;
13517c478bdstevel@tonic-gate
13527c478bdstevel@tonic-gate				case Qhdr_Connection_close:
13537c478bdstevel@tonic-gate					persist = B_FALSE;
13547c478bdstevel@tonic-gate					break;
13557c478bdstevel@tonic-gate
13567c478bdstevel@tonic-gate				case Qhdr_Connection_Keep_Alive:
13577c478bdstevel@tonic-gate					persist = B_TRUE;
13587c478bdstevel@tonic-gate					break;
13597c478bdstevel@tonic-gate
13607c478bdstevel@tonic-gate				case Qhdr_Date:
13617c478bdstevel@tonic-gate					http->date = secs;
13627c478bdstevel@tonic-gate					break;
13637c478bdstevel@tonic-gate
13647c478bdstevel@tonic-gate				case Qhdr_ETag:
13657c478bdstevel@tonic-gate					http->etag.cp = hp;
13667c478bdstevel@tonic-gate					http->etag.ep = ep;
13677c478bdstevel@tonic-gate					break;
13687c478bdstevel@tonic-gate
13697c478bdstevel@tonic-gate				case Qhdr_Host:
13707c478bdstevel@tonic-gate					uri->auth.cp = hp;
13717c478bdstevel@tonic-gate					uri->auth.ep = ep;
13727c478bdstevel@tonic-gate					break;
13737c478bdstevel@tonic-gate
13747c478bdstevel@tonic-gate				case Qhdr_If_Modified_Since:
13757c478bdstevel@tonic-gate				case Qhdr_If_Unmodified_Since:
13762c9e429brutus					http->moddate = secs;
13772c9e429brutus					http->modtokid = match->tokid;
13782c9e429brutus					uri->conditional = B_TRUE;
13797c478bdstevel@tonic-gate					break;
13807c478bdstevel@tonic-gate
13817c478bdstevel@tonic-gate				case Qhdr_Keep_Alive:
13827c478bdstevel@tonic-gate					persist = B_TRUE;
13837c478bdstevel@tonic-gate					break;
13847c478bdstevel@tonic-gate
13857c478bdstevel@tonic-gate				case Qhdr_User_Agent:
13867c478bdstevel@tonic-gate					http->uagent.cp = hp;
13877c478bdstevel@tonic-gate					http->uagent.ep = ep;
13887c478bdstevel@tonic-gate					break;
13897c478bdstevel@tonic-gate
13907c478bdstevel@tonic-gate				default:
13917c478bdstevel@tonic-gate					break;
13927c478bdstevel@tonic-gate
13937c478bdstevel@tonic-gate				};
13947c478bdstevel@tonic-gate			}
13952c9e429brutus			if (match->act & FILTER) {
13962c9e429brutus				/*
13972c9e429brutus				 * Filter header, do a copyover the header
13982c9e429brutus				 * text, guarenteed to be at least 1 byte.
13992c9e429brutus				 */
14002c9e429brutus				char	*cop = scp;
14012c9e429brutus				int	n = (ep - cop) - 1;
14022c9e429brutus				char	filter[] = "NL7C-Filtered";
14032c9e429brutus
14042c9e429brutus				n = MIN(n, sizeof (filter) - 1);
14052c9e429brutus				if (n > 0)
14062c9e429brutus					bcopy(filter, cop, n);
14072c9e429brutus				cop += n;
14082c9e429brutus				ASSERT(cop < ep);
14092c9e429brutus				*cop++ = ':';
14102c9e429brutus				while (cop < ep)
14112c9e429brutus					*cop++ = ' ';
14122c9e429brutus			}
14137c478bdstevel@tonic-gate			if (match->act & NOCACHE) {
14147c478bdstevel@tonic-gate				uri->nocache = B_TRUE;
14157c478bdstevel@tonic-gate			}
14167c478bdstevel@tonic-gate		} else if (hp == NULL) {
14177c478bdstevel@tonic-gate			goto done;
14187c478bdstevel@tonic-gate		} else if (ep == NULL) {
14197c478bdstevel@tonic-gate			goto more;
14207c478bdstevel@tonic-gate		}
14217c478bdstevel@tonic-gate	}
14227c478bdstevel@tonic-gate	/* No EOH found */
14237c478bdstevel@tonic-gate	goto more;
14247c478bdstevel@tonic-gate
14257c478bdstevel@tonic-gatedone:
14267c478bdstevel@tonic-gate	/*
14277c478bdstevel@tonic-gate	 * Initialize socket persist state and response persist type
14287c478bdstevel@tonic-gate	 * flag based on the persist state of the request headers.
14297c478bdstevel@tonic-gate	 *
14307c478bdstevel@tonic-gate	 */
14317c478bdstevel@tonic-gate	if (persist)
14320f1702cYu Xiangning<Eric.Yu@Sun.COM>		sti->sti_nl7c_flags |= NL7C_SOPERSIST;
14337c478bdstevel@tonic-gate	else
14340f1702cYu Xiangning<Eric.Yu@Sun.COM>		sti->sti_nl7c_flags &= ~NL7C_SOPERSIST;
14357c478bdstevel@tonic-gate
14367c478bdstevel@tonic-gate	if (http->major == 1) {
14370f1702cYu Xiangning<Eric.Yu@Sun.COM>		sti->sti_nl7c_flags &= ~NL7C_SCHEMEPRIV;
14387c478bdstevel@tonic-gate		if (http->minor >= 1) {
14397c478bdstevel@tonic-gate			if (! persist)
14400f1702cYu Xiangning<Eric.Yu@Sun.COM>				sti->sti_nl7c_flags |= HTTP_CONN_CL;
14417c478bdstevel@tonic-gate		} else {
14427c478bdstevel@tonic-gate			if (persist)
14430f1702cYu Xiangning<Eric.Yu@Sun.COM>				sti->sti_nl7c_flags |= HTTP_CONN_KA;
14447c478bdstevel@tonic-gate			else
14450f1702cYu Xiangning<Eric.Yu@Sun.COM>				sti->sti_nl7c_flags |= HTTP_CONN_CL;
14467c478bdstevel@tonic-gate		}
14477c478bdstevel@tonic-gate	}
14487c478bdstevel@tonic-gate	/*
14497c478bdstevel@tonic-gate	 * Last, update parse consumed text pointer.
14507c478bdstevel@tonic-gate	 */
14517c478bdstevel@tonic-gate	*cpp = cp;
14527c478bdstevel@tonic-gate	return (B_TRUE);
14537c478bdstevel@tonic-gate
14547c478bdstevel@tonic-gatepass:
14557c478bdstevel@tonic-gate	*cpp = NULL;
14562c9e429brutus	return (B_TRUE);
14572c9e429brutus
14582c9e429brutusbad:
14592c9e429brutus	*cpp = NULL;
14607c478bdstevel@tonic-gatemore:
14617c478bdstevel@tonic-gate	return (B_FALSE);
14627c478bdstevel@tonic-gate}
14637c478bdstevel@tonic-gate
14647c478bdstevel@tonic-gateboolean_t
14657c478bdstevel@tonic-gatenl7c_http_response(char **cpp, char *ep, uri_desc_t *uri, struct sonode *so)
14667c478bdstevel@tonic-gate{
14670f1702cYu Xiangning<Eric.Yu@Sun.COM>	sotpi_info_t *sti = SOTOTPI(so);
14687c478bdstevel@tonic-gate	http_t	*http = uri->scheme;
14697c478bdstevel@tonic-gate	char	*cp = *cpp;
14707c478bdstevel@tonic-gate	char	*hp;
14717c478bdstevel@tonic-gate	char	*scp, *sep;
14727c478bdstevel@tonic-gate	char	*HTTP = "HTTP/";
14737c478bdstevel@tonic-gate	int	status = 0;
14747c478bdstevel@tonic-gate	token_t	*match;
14757c478bdstevel@tonic-gate#ifdef	NOT_YET
14767c478bdstevel@tonic-gate	uint32_t major, minor;
14777c478bdstevel@tonic-gate#endif
14787c478bdstevel@tonic-gate	boolean_t nocache = B_FALSE;
14797c478bdstevel@tonic-gate	boolean_t persist = B_FALSE;
14807c478bdstevel@tonic-gate
14817c478bdstevel@tonic-gate	ASSERT(http != NULL);
14827c478bdstevel@tonic-gate
14832c9e429brutus	if (http->parsed) {
14842c9e429brutus		if (uri->respclen != URI_LEN_NOVALUE) {
14852c9e429brutus			/* Chunked response */
14862c9e429brutus			sep = ep;
14872c9e429brutus			goto chunked;
14882c9e429brutus		}
14892c9e429brutus		/* Already parsed, nothing todo */
14907c478bdstevel@tonic-gate		return (B_TRUE);
14912c9e429brutus	}
14927c478bdstevel@tonic-gate
14937c478bdstevel@tonic-gate	/*
14947c478bdstevel@tonic-gate	 * Parse the HTTP/N.N version. Note, there's currently no use
14957c478bdstevel@tonic-gate	 * for the actual response major nor minor values as only the
14967c478bdstevel@tonic-gate	 * request values are used.
14977c478bdstevel@tonic-gate	 */
14987c478bdstevel@tonic-gate	while (cp < ep && *HTTP == *cp) {
14997c478bdstevel@tonic-gate		HTTP++;
15007c478bdstevel@tonic-gate		cp++;
15017c478bdstevel@tonic-gate	}
15027c478bdstevel@tonic-gate	if (*HTTP != 0) {
15037c478bdstevel@tonic-gate		if (cp == ep)
15047c478bdstevel@tonic-gate			goto more;
15052c9e429brutus		goto bad;
15067c478bdstevel@tonic-gate	}
15077c478bdstevel@tonic-gate	if (cp == ep)
15087c478bdstevel@tonic-gate		goto more;
15097c478bdstevel@tonic-gate
15107c478bdstevel@tonic-gate	if (*cp < '0' || *cp > '9')
15112c9e429brutus		goto bad;
15127c478bdstevel@tonic-gate#ifdef	NOT_YET
15137c478bdstevel@tonic-gate	major = *cp++ - '0';
15147c478bdstevel@tonic-gate#else
15157c478bdstevel@tonic-gate	cp++;
15167c478bdstevel@tonic-gate#endif
15177c478bdstevel@tonic-gate
15187c478bdstevel@tonic-gate	if (cp == ep)
15197c478bdstevel@tonic-gate		goto more;
15207c478bdstevel@tonic-gate	if (*cp++ != '.')
15212c9e429brutus		goto bad;
15227c478bdstevel@tonic-gate	if (cp == ep)
15237c478bdstevel@tonic-gate		goto more;
15247c478bdstevel@tonic-gate	if (*cp < '0' || *cp > '9')
15252c9e429brutus		goto bad;
15267c478bdstevel@tonic-gate#ifdef	NOT_YET
15277c478bdstevel@tonic-gate	minor = *cp++ - '0';
15287c478bdstevel@tonic-gate#else
15297c478bdstevel@tonic-gate	cp++;
15307c478bdstevel@tonic-gate#endif
15317c478bdstevel@tonic-gate
15327c478bdstevel@tonic-gate	if (cp == ep)
15337c478bdstevel@tonic-gate		goto more;
15347c478bdstevel@tonic-gate
15357c478bdstevel@tonic-gategot_version:
15367c478bdstevel@tonic-gate
15377c478bdstevel@tonic-gate	/*
15382c9e429brutus	 * Get the response code.
15397c478bdstevel@tonic-gate	 */
15407c478bdstevel@tonic-gate	if (*cp++ != ' ')
15412c9e429brutus		goto bad;
15427c478bdstevel@tonic-gate	if (cp == ep)
15437c478bdstevel@tonic-gate		goto more;
15447c478bdstevel@tonic-gate
15457c478bdstevel@tonic-gate	do {
15467c478bdstevel@tonic-gate		if (*cp == ' ')
15477c478bdstevel@tonic-gate			break;
15487c478bdstevel@tonic-gate		if (*cp < '0' || *cp > '9')
15492c9e429brutus			goto bad;
15507c478bdstevel@tonic-gate		if (status)
15517c478bdstevel@tonic-gate			status *= 10;
15527c478bdstevel@tonic-gate		status += *cp++ - '0';
15537c478bdstevel@tonic-gate	} while (cp < ep);
15547c478bdstevel@tonic-gate
15552c9e429brutus	switch (status) {
15562c9e429brutus	case 200:
15572c9e429brutus		/*
15582c9e429brutus		 * The only response status we continue to process.
15592c9e429brutus		 */
15602c9e429brutus		break;
15612c9e429brutus	case 304:
15622c9e429brutus		nl7c_http_response_304++;
15632c9e429brutus		nocache = B_TRUE;
15642c9e429brutus		uri->resplen = 0;
15652c9e429brutus		goto pass;
15662c9e429brutus	case 307:
15672c9e429brutus		nl7c_http_response_307++;
15682c9e429brutus		nocache = B_TRUE;
15692c9e429brutus		uri->resplen = 0;
15702c9e429brutus		goto pass;
15712c9e429brutus	case 400:
15722c9e429brutus		nl7c_http_response_400++;
15732c9e429brutus		/*
15742c9e429brutus		 * Special case some response status codes, just mark
15752c9e429brutus		 * as nocache and no response length and pass on the
15762c9e429brutus		 * request/connection.
15772c9e429brutus		 */
15782c9e429brutus		nocache = B_TRUE;
15792c9e429brutus		uri->resplen = 0;
15807c478bdstevel@tonic-gate		goto pass;
15812c9e429brutus	default:
15822c9e429brutus		/*
15832c9e429brutus		 * All other response codes result in a parse failure.
15842c9e429brutus		 */
15852c9e429brutus		goto bad;
15862c9e429brutus	}
15877c478bdstevel@tonic-gate
15887c478bdstevel@tonic-gate	/*
15897c478bdstevel@tonic-gate	 * Initialize persistent state based on request HTTP version.
15907c478bdstevel@tonic-gate	 */
15917c478bdstevel@tonic-gate	if (http->major == 1) {
15927c478bdstevel@tonic-gate		if (http->minor >= 1) {
15937c478bdstevel@tonic-gate			/* 1.1 persistent by default */
15947c478bdstevel@tonic-gate			persist = B_TRUE;
15957c478bdstevel@tonic-gate		} else {
15967c478bdstevel@tonic-gate			/* 1.0 isn't persistent by default */
15977c478bdstevel@tonic-gate			persist = B_FALSE;
15987c478bdstevel@tonic-gate		}
15997c478bdstevel@tonic-gate	} else if (http->major == 0) {
16007c478bdstevel@tonic-gate		/* Before 1.0 no persistent connections */
16017c478bdstevel@tonic-gate		persist = B_FALSE;
16027c478bdstevel@tonic-gate	} else {
16037c478bdstevel@tonic-gate		/* >= 2.0 not supported (yet) */
16042c9e429brutus		goto bad;
16057c478bdstevel@tonic-gate	}
16067c478bdstevel@tonic-gate
16077c478bdstevel@tonic-gate	/*
16087c478bdstevel@tonic-gate	 * Parse HTTP headers through the EOH
16097c478bdstevel@tonic-gate	 * (End Of Header, i.e. an empty line).
16107c478bdstevel@tonic-gate	 */
16117c478bdstevel@tonic-gate	for (sep = ep; cp < ep; ep = sep) {
16127c478bdstevel@tonic-gate		/* Get the next line */
16137c478bdstevel@tonic-gate		scp = cp;
16142c9e429brutus		match = ttree_line_parse(res_tree, &cp, &ep, &hp, NULL);
16157c478bdstevel@tonic-gate		if (match != NULL) {
16167c478bdstevel@tonic-gate			if (match->act & QUALIFIER) {
16177c478bdstevel@tonic-gate				/*
16187c478bdstevel@tonic-gate				 * Header field text is used to qualify this
16197c478bdstevel@tonic-gate				 * request/response, based on qualifier type
16207c478bdstevel@tonic-gate				 * optionally convert and store *http.
16217c478bdstevel@tonic-gate				 */
16227c478bdstevel@tonic-gate				char	c;
16237c478bdstevel@tonic-gate				int	n = 0;
16247c478bdstevel@tonic-gate				time_t	secs;
16257c478bdstevel@tonic-gate
16267c478bdstevel@tonic-gate				ASSERT(hp != NULL && ep != NULL);
16277c478bdstevel@tonic-gate
16287c478bdstevel@tonic-gate				if (match->act & NUMERIC) {
16297c478bdstevel@tonic-gate					while (hp < ep) {
16307c478bdstevel@tonic-gate						c = *hp++;
16312c9e429brutus						if (match->act & HEX) {
16322c9e429brutus							hd2i(c, n);
16332c9e429brutus							if (n == -1)
16342c9e429brutus								goto bad;
16352c9e429brutus						} else {
16362c9e429brutus							if (! isdigit(c))
16372c9e429brutus								goto bad;
16382c9e429brutus							n *= 10;
16392c9e429brutus							n += c - '0';
16402c9e429brutus						}
16417c478bdstevel@tonic-gate					}
16427c478bdstevel@tonic-gate				} else if (match->act & DATE) {
16437c478bdstevel@tonic-gate					secs = http_date2time_t(hp, ep);
16447c478bdstevel@tonic-gate				}
16457c478bdstevel@tonic-gate				switch (match->tokid) {
16467c478bdstevel@tonic-gate
16477c478bdstevel@tonic-gate				case Shdr_Cache_Control_Max_Age:
16487c478bdstevel@tonic-gate					break;
16497c478bdstevel@tonic-gate
16507c478bdstevel@tonic-gate				case Shdr_Cache_Control_No_Cache:
16517c478bdstevel@tonic-gate					nocache = B_TRUE;
16527c478bdstevel@tonic-gate					break;
16537c478bdstevel@tonic-gate
16547c478bdstevel@tonic-gate				case Shdr_Cache_Control_No_Store:
16557c478bdstevel@tonic-gate					nocache = B_TRUE;
16567c478bdstevel@tonic-gate					break;
16577c478bdstevel@tonic-gate
16587c478bdstevel@tonic-gate				case Shdr_Connection_close:
16597c478bdstevel@tonic-gate					persist = B_FALSE;
16607c478bdstevel@tonic-gate					break;
16617c478bdstevel@tonic-gate
16627c478bdstevel@tonic-gate				case Shdr_Connection_Keep_Alive:
16637c478bdstevel@tonic-gate					persist = B_TRUE;
16647c478bdstevel@tonic-gate					break;
16657c478bdstevel@tonic-gate
16662c9e429brutus				case Shdr_Chunked:
16672c9e429brutus					uri->respclen = 0;
16682c9e429brutus					uri->resplen = 0;
16692c9e429brutus					nl7c_http_response_chunked++;
16702c9e429brutus					break;
16712c9e429brutus
16727c478bdstevel@tonic-gate				case Shdr_Content_Length:
16732c9e429brutus					if (uri->respclen == URI_LEN_NOVALUE)
16742c9e429brutus						uri->resplen = n;
16757c478bdstevel@tonic-gate					break;
16767c478bdstevel@tonic-gate
16777c478bdstevel@tonic-gate				case Shdr_Date:
16787c478bdstevel@tonic-gate					http->date = secs;
16797c478bdstevel@tonic-gate					break;
16807c478bdstevel@tonic-gate
16817c478bdstevel@tonic-gate				case Shdr_ETag:
16827c478bdstevel@tonic-gate					http->etag.cp = hp;
16837c478bdstevel@tonic-gate					http->etag.ep = ep;
16847c478bdstevel@tonic-gate					break;
16857c478bdstevel@tonic-gate
16867c478bdstevel@tonic-gate				case Shdr_Expires:
16877c478bdstevel@tonic-gate					http->expire = secs;
16887c478bdstevel@tonic-gate					break;
16897c478bdstevel@tonic-gate
16907c478bdstevel@tonic-gate				case Shdr_Keep_Alive:
16917c478bdstevel@tonic-gate					persist = B_TRUE;
16927c478bdstevel@tonic-gate					break;
16937c478bdstevel@tonic-gate
16947c478bdstevel@tonic-gate				case Shdr_Last_Modified:
16957c478bdstevel@tonic-gate					http->lastmod = secs;
16967c478bdstevel@tonic-gate					break;
16977c478bdstevel@tonic-gate
16982c9e429brutus				case Shdr_Set_Cookie:
16997c478bdstevel@tonic-gate					nocache = B_TRUE;
17002c9e429brutus					break;
17012c9e429brutus
17022c9e429brutus				case Shdr_Server:
17032c9e429brutus					break;
17047c478bdstevel@tonic-gate
17057c478bdstevel@tonic-gate				default:
17067c478bdstevel@tonic-gate					nocache = B_TRUE;
17077c478bdstevel@tonic-gate					break;
17087c478bdstevel@tonic-gate				};
17097c478bdstevel@tonic-gate			}
17107c478bdstevel@tonic-gate			if (match->act & FILTER) {
17117c478bdstevel@tonic-gate				/*
17127c478bdstevel@tonic-gate				 * Filter header, do a copyover the header
17137c478bdstevel@tonic-gate				 * text, guarenteed to be at least 1 byte.
17147c478bdstevel@tonic-gate				 */
17157c478bdstevel@tonic-gate				char	*cop = scp;
17167c478bdstevel@tonic-gate				int	n = (ep - cop) - 1;
17177c478bdstevel@tonic-gate				char	filter[] = "NL7C-Filtered";
17187c478bdstevel@tonic-gate
17197c478bdstevel@tonic-gate				n = MIN(n, sizeof (filter) - 1);
17207c478bdstevel@tonic-gate				if (n > 0)
17217c478bdstevel@tonic-gate					bcopy(filter, cop, n);
17227c478bdstevel@tonic-gate				cop += n;
17237c478bdstevel@tonic-gate				ASSERT(cop < ep);
17247c478bdstevel@tonic-gate				*cop++ = ':';
17257c478bdstevel@tonic-gate				while (cop < ep)
17267c478bdstevel@tonic-gate					*cop++ = ' ';
17277c478bdstevel@tonic-gate			}
17287c478bdstevel@tonic-gate			if (match->act & NOCACHE) {
17297c478bdstevel@tonic-gate				nocache = B_TRUE;
17307c478bdstevel@tonic-gate			}
17317c478bdstevel@tonic-gate		} else if (hp == NULL) {
17327c478bdstevel@tonic-gate			uri->eoh = scp;
17337c478bdstevel@tonic-gate			goto done;
17347c478bdstevel@tonic-gate		} else if (ep == NULL) {
17357c478bdstevel@tonic-gate			goto more;
17367c478bdstevel@tonic-gate		}
17377c478bdstevel@tonic-gate	}
17387c478bdstevel@tonic-gate	/* No EOH found */
17397c478bdstevel@tonic-gate	goto more;
17407c478bdstevel@tonic-gate
17417c478bdstevel@tonic-gatedone:
17422c9e429brutus	/* Parse completed */
17437c478bdstevel@tonic-gate	http->parsed = B_TRUE;
17442c9e429brutus	/* Save the HTTP header length */
17457c478bdstevel@tonic-gate	http->headlen = (cp - *cpp);
17462c9e429brutus	if (uri->respclen == URI_LEN_NOVALUE) {
17472c9e429brutus		if (uri->resplen == URI_LEN_NOVALUE) {
17482c9e429brutus			nl7c_http_response_pass1++;
17492c9e429brutus			goto pass;
17502c9e429brutus		}
17512c9e429brutus	}
17522c9e429brutus	/* Add header length to URI response length */
17537c478bdstevel@tonic-gate	uri->resplen += http->headlen;
17547c478bdstevel@tonic-gate
17557c478bdstevel@tonic-gate	/* Set socket persist state */
17567c478bdstevel@tonic-gate	if (persist)
17570f1702cYu Xiangning<Eric.Yu@Sun.COM>		sti->sti_nl7c_flags |= NL7C_SOPERSIST;
17587c478bdstevel@tonic-gate	else
17590f1702cYu Xiangning<Eric.Yu@Sun.COM>		sti->sti_nl7c_flags &= ~NL7C_SOPERSIST;
17607c478bdstevel@tonic-gate
17612c9e429brutus	if (http->major == 1) {
17620f1702cYu Xiangning<Eric.Yu@Sun.COM>		sti->sti_nl7c_flags &= ~NL7C_SCHEMEPRIV;
17632c9e429brutus		if (http->minor >= 1) {
17642c9e429brutus			if (! persist)
17650f1702cYu Xiangning<Eric.Yu@Sun.COM>				sti->sti_nl7c_flags |= HTTP_CONN_CL;
17662c9e429brutus		} else {
17672c9e429brutus			if (persist)
17680f1702cYu Xiangning<Eric.Yu@Sun.COM>				sti->sti_nl7c_flags |= HTTP_CONN_KA;
17692c9e429brutus			else
17700f1702cYu Xiangning<Eric.Yu@Sun.COM>				sti->sti_nl7c_flags |= HTTP_CONN_CL;
17712c9e429brutus		}
17722c9e429brutus	}
17732c9e429brutus
17742c9e429brutus	if (nocache) {
17752c9e429brutus		/*
17762c9e429brutus		 * Response not to be cached, only post response
17772c9e429brutus		 * processing code common to both non and cached
17782c9e429brutus		 * cases above here and code for the cached case
17792c9e429brutus		 * below.
17802c9e429brutus		 *
17812c9e429brutus		 * Note, chunked transfer processing is the last
17822c9e429brutus		 * to be done.
17832c9e429brutus		 */
17842c9e429brutus		uri->nocache = B_TRUE;
17852c9e429brutus		if (uri->respclen != URI_LEN_NOVALUE) {
17862c9e429brutus			/* Chunked response */
17872c9e429brutus			goto chunked;
17882c9e429brutus		}
17892c9e429brutus		/* Nothing more todo */
17902c9e429brutus		goto parsed;
17912c9e429brutus	}
17922c9e429brutus
17937c478bdstevel@tonic-gate	if (http->expire != -1 && http->date != -1) {
17947c478bdstevel@tonic-gate		if (http->expire <= http->date) {
17952c9e429brutus			/* ??? just pass */
17962c9e429brutus			nl7c_http_response_pass2++;
17977c478bdstevel@tonic-gate			goto pass;
17987c478bdstevel@tonic-gate		}
17997c478bdstevel@tonic-gate		/* Have a valid expire and date so calc an lbolt expire */
1800d3d5073Rafael Vanoni		uri->expire = ddi_get_lbolt() + SEC_TO_TICK(http->expire -
1801d3d5073Rafael Vanoni		    http->date);
18027c478bdstevel@tonic-gate	} else if (nl7c_uri_ttl != -1) {
18037c478bdstevel@tonic-gate		/* No valid expire speced and we have a TTL */
1804d3d5073Rafael Vanoni		uri->expire = ddi_get_lbolt() + SEC_TO_TICK(nl7c_uri_ttl);
18057c478bdstevel@tonic-gate	}
18067c478bdstevel@tonic-gate
18072c9e429brutuschunked:
18082c9e429brutus	/*
18092c9e429brutus	 * Chunk transfer parser and processing, a very simple parser
18102c9e429brutus	 * is implemented here for the common case were one, or more,
18112c9e429brutus	 * complete chunk(s) are passed in (i.e. length header + body).
18122c9e429brutus	 *
18132c9e429brutus	 * All other cases are passed.
18142c9e429brutus	 */
18152c9e429brutus	scp = cp;
18162c9e429brutus	while (uri->respclen != URI_LEN_NOVALUE && cp < sep) {
18172c9e429brutus		if (uri->respclen == URI_LEN_CONSUMED) {
18182c9e429brutus			/* Skip trailing "\r\n" */
18192c9e429brutus			if (cp == sep)
18202c9e429brutus				goto more;
18212c9e429brutus			if (*cp++ != '\r')
18222c9e429brutus				goto bad;
18232c9e429brutus			if (cp == sep)
18242c9e429brutus				goto more;
18252c9e429brutus			if (*cp++ != '\n')
18262c9e429brutus				goto bad;
18272c9e429brutus			uri->respclen = 0;
18282c9e429brutus		}
18292c9e429brutus		if (uri->respclen == 0) {
18302c9e429brutus			/* Parse a chunklen "[0-9A-Fa-f]+" */
18312c9e429brutus			char	c;
18322c9e429brutus			int	n = 0;
18332c9e429brutus
18342c9e429brutus			if (cp == sep)
18352c9e429brutus				goto more;
18362c9e429brutus			nl7c_http_response_chunkparse++;
18372c9e429brutus			while (cp < sep && (c = *cp++) != '\r') {
18382c9e429brutus				hd2i(c, n);
18392c9e429brutus				if (n == -1)
18402c9e429brutus					goto bad;
18412c9e429brutus			}
18422c9e429brutus			if (cp == sep)
18432c9e429brutus				goto more;
18442c9e429brutus			if (*cp++ != '\n')
18452c9e429brutus				goto bad;
18462c9e429brutus			uri->respclen = n;
18472c9e429brutus			if (n == 0) {
18482c9e429brutus				/* Last chunk, skip trailing "\r\n" */
18492c9e429brutus				if (cp == sep)
18502c9e429brutus					goto more;
18512c9e429brutus				if (*cp++ != '\r')
18522c9e429brutus					goto bad;
18532c9e429brutus				if (cp == sep)
18542c9e429brutus					goto more;
18552c9e429brutus				if (*cp++ != '\n')
18562c9e429brutus					goto bad;
18572c9e429brutus				uri->respclen = URI_LEN_NOVALUE;
18582c9e429brutus				break;
18592c9e429brutus			}
18602c9e429brutus		}
18612c9e429brutus		if (uri->respclen > 0) {
18622c9e429brutus			/* Consume some bytes for the current chunk */
18632c9e429brutus			uint32_t sz = (sep - cp);
18642c9e429brutus
18652c9e429brutus			if (sz > uri->respclen)
18662c9e429brutus				sz = uri->respclen;
18672c9e429brutus			uri->respclen -= sz;
18682c9e429brutus			cp += sz;
18692c9e429brutus			if (uri->respclen == 0) {
18702c9e429brutus				/* End of chunk, skip trailing "\r\n" */
18712c9e429brutus				if (cp == sep) {
18722c9e429brutus					uri->respclen = URI_LEN_CONSUMED;
18732c9e429brutus					goto more;
18742c9e429brutus				}
18752c9e429brutus				if (*cp++ != '\r')
18762c9e429brutus					goto bad;
18772c9e429brutus				if (cp == sep)
18782c9e429brutus					goto more;
18792c9e429brutus				if (*cp++ != '\n')
18802c9e429brutus					goto bad;
18812c9e429brutus				if (cp == sep)
18822c9e429brutus					goto more;
18832c9e429brutus			}
18842c9e429brutus		}
18852c9e429brutus	}
18862c9e429brutus	uri->resplen += (cp - scp);
18872c9e429brutus
18882c9e429brutusparsed:
18897c478bdstevel@tonic-gate	*cpp = cp;
18907c478bdstevel@tonic-gate	return (B_TRUE);
18917c478bdstevel@tonic-gate
18927c478bdstevel@tonic-gatepass:
18937c478bdstevel@tonic-gate	*cpp = NULL;
18942c9e429brutus	return (B_TRUE);
18952c9e429brutus
18962c9e429brutusbad:
18972c9e429brutus	*cpp = NULL;
18982c9e429brutus	return (B_FALSE);
18992c9e429brutus
19007c478bdstevel@tonic-gatemore:
19012c9e429brutus	uri->resplen += (cp - scp);
19022c9e429brutus	*cpp = cp;
19037c478bdstevel@tonic-gate	return (B_FALSE);
19047c478bdstevel@tonic-gate}
19057c478bdstevel@tonic-gate
19067c478bdstevel@tonic-gateboolean_t
19077c478bdstevel@tonic-gatenl7c_http_log(uri_desc_t *quri, uri_desc_t *suri, nca_request_log_t *req,
19087c478bdstevel@tonic-gate    char **wp, char **pep, uint32_t *off)
19097c478bdstevel@tonic-gate{
19107c478bdstevel@tonic-gate	http_t	*qhttp = quri->scheme;
19117c478bdstevel@tonic-gate	http_t	*shttp = suri->scheme;
19127c478bdstevel@tonic-gate	int	sz;
19137c478bdstevel@tonic-gate
19147c478bdstevel@tonic-gate	if (qhttp->uagent.cp != NULL) {
19157c478bdstevel@tonic-gate		sz = (qhttp->uagent.ep - qhttp->uagent.cp);
19167c478bdstevel@tonic-gate		if ((*wp + sz + 1) >= *pep) goto full;
19177c478bdstevel@tonic-gate		bcopy(qhttp->uagent.cp, *wp, sz);
19187c478bdstevel@tonic-gate		*wp += sz;
19197c478bdstevel@tonic-gate		*(*wp)++ = 0;
19207c478bdstevel@tonic-gate		sz++;
19217c478bdstevel@tonic-gate		req->useragent_len = sz;
19227c478bdstevel@tonic-gate		req->useragent = *off;
19237c478bdstevel@tonic-gate		*off += sz;
19247c478bdstevel@tonic-gate	}
19257c478bdstevel@tonic-gate
19267c478bdstevel@tonic-gate	req->response_len -= (uint_t)shttp->headlen;
19277c478bdstevel@tonic-gate
19287c478bdstevel@tonic-gate	req->method = NCA_GET;
19297c478bdstevel@tonic-gate
19307c478bdstevel@tonic-gate	if (qhttp->major == 1) {
19317c478bdstevel@tonic-gate		if (qhttp->minor == 0) {
19327c478bdstevel@tonic-gate			req->version = HTTP_1_0;
19337c478bdstevel@tonic-gate		} else if (qhttp->minor == 1) {
19347c478bdstevel@tonic-gate			req->version = HTTP_1_1;
19357c478bdstevel@tonic-gate		} else {
19367c478bdstevel@tonic-gate			req->version = HTTP_0_0;
19377c478bdstevel@tonic-gate		}
19387c478bdstevel@tonic-gate	} else if (qhttp->major == 0) {
19397c478bdstevel@tonic-gate		req->version = HTTP_0_9;
19407c478bdstevel@tonic-gate	} else {
19417c478bdstevel@tonic-gate		req->version = HTTP_0_0;
19427c478bdstevel@tonic-gate	}
19437c478bdstevel@tonic-gate
19447c478bdstevel@tonic-gate	return (B_FALSE);
19457c478bdstevel@tonic-gate
19467c478bdstevel@tonic-gatefull:
19477c478bdstevel@tonic-gate	return (B_TRUE);
19487c478bdstevel@tonic-gate}
1949