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