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