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 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 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 * 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 * 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 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 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 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 * 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 * 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 * 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 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 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 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