/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
*/
#include <sys/sysmacros.h>
#include <sys/condvar_impl.h>
#include <sys/sendfile.h>
/*
* Some externs:
*/
extern boolean_t nl7c_logd_enabled;
extern struct sonode *nl7c_addr2portso(void *);
/*
* Various global tuneables:
*/
/*
* Locals:
*/
/*
* HTTP scheme functions called from nl7chttp.c:
*/
boolean_t nl7c_http_cmp(void *, void *);
void nl7c_http_free(void *arg);
void nl7c_http_init(void);
/*
*/
/*
* Various kmem_cache_t's:
*/
static void uri_kmc_reclaim(void *);
static void nl7c_uri_reclaim(void);
/*
* The URI hash is a dynamically sized A/B bucket hash, when the current
* hash's average bucket chain length exceeds URI_HASH_AVRG a new hash of
* the next P2Ps[] size is created.
*
* All lookups are done in the current hash then the new hash (if any),
* if there is a new has then when a current hash bucket chain is examined
* any uri_desc_t members will be migrated to the new hash and when the
* last uri_desc_t has been migrated then the new hash will become the
* current and the previous current hash will be freed leaving a single
* hash.
*
* uri_hash_t - hash bucket (chain) type, contained in the uri_hash_ab[]
* and can be accessed only after aquiring the uri_hash_access lock (for
* READER or WRITER) then acquiring the lock uri_hash_t.lock, the uri_hash_t
* and all linked uri_desc_t.hash members are protected. Note, a REF_HOLD()
* is placed on all uri_desc_t uri_hash_t list members.
*
* uri_hash_access - rwlock for all uri_hash_* variables, READER for read
* access and WRITER for write access. Note, WRITER is only required for
* hash geometry changes.
*
* uri_hash_which - which uri_hash_ab[] is the current hash.
*
* uri_hash_n[] - the P2Ps[] index for each uri_hash_ab[].
*
* uri_hash_sz[] - the size for each uri_hash_ab[].
*
* uri_hash_cnt[] - the total uri_desc_t members for each uri_hash_ab[].
*
* uri_hash_overflow[] - the uri_hash_cnt[] for each uri_hash_ab[] when
* a new uri_hash_ab[] needs to be created.
*
* uri_hash_ab[] - the uri_hash_t entries.
*
* uri_hash_lru[] - the last uri_hash_ab[] walked for lru reclaim.
*/
typedef struct uri_hash_s {
} uri_hash_t;
/*
* Primes for N of 3 - 24 where P is first prime less then (2^(N-1))+(2^(N-2))
* these primes have been foud to be useful for prime sized hash tables.
*/
static const int P2Ps[] = {
0, 0, 0, 5, 11, 23, 47, 89, 191, 383, 761, 1531, 3067,
6143, 12281, 24571, 49139, 98299, 196597, 393209,
786431, 1572853, 3145721, 6291449, 12582893, 0};
/*
* Hash macros:
*
* H2A(char *cp, char *ep, char c) - convert the escaped octet (ASCII)
* hex multichar of the format "%HH" pointeded to by *cp to a char and
* return in c, *ep points to past end of (char *), on return *cp will
* point to the last char consumed.
*
* URI_HASH(unsigned hix, char *cp, char *ep) - hash the char(s) from
* *cp to *ep to the unsigned hix, cp nor ep are modified.
*
* URI_HASH_IX(unsigned hix, int which) - convert the hash value hix to
* a hash index 0 - (uri_hash_sz[which] - 1).
*
* URI_HASH_MIGRATE(from, hp, to) - migrate the uri_hash_t *hp list
* uri_desc_t members from hash from to hash to.
*
* URI_HASH_UNLINK(cur, new, hp, puri, uri) - unlink the uri_desc_t
* *uri which is a member of the uri_hash_t *hp list with a previous
* list member of *puri for the uri_hash_ab[] cur. After unlinking
* check for cur hash empty, if so make new cur. Note, as this macro
* can change a hash chain it needs to be run under hash_access as
* RW_WRITER, futher as it can change the new hash to cur any access
* to the hash state must be done after either dropping locks and
* starting over or making sure the global state is consistent after
* as before.
*/
int _h = 2; \
int _n = 0; \
char _hc; \
\
if (_h == 1) \
_n *= 0x10; \
_h--; \
} \
(c) = _n; \
}
char _c; \
\
} \
_s++; \
} \
}
uri_desc_t *_nuri; \
uri_hash_t *_nhp; \
\
} \
}
} else { \
} \
uri_hash_which = (new); \
} else { \
} \
}
void
nl7c_uri_init(void)
{
KM_SLEEP);
}
void
{
next:
for (n = 0; n <= CV_SZ; n++)
cv[n] = 0;
nz = 0;
tot = 0;
n = 0;
n++;
}
tot += n;
if (n > 0)
nz++;
if (n > CV_SZ)
n = CV_SZ;
cv[n]++;
hp++;
}
for (n = 1; n < CV_SZ; n++) {
int pn = 0;
*pp++ = ' ';
*pp = 0;
}
goto next;
}
}
void
{
int ix;
int ret;
char sc;
next:
if (ret == -1) break;
}
if (ret == -1) break;
}
goto next;
}
}
/*
* The uri_desc_t ref_t inactive function called on the last REF_RELE(),
* free all resources contained in the uri_desc_t. Note, the uri_desc_t
* will be freed by REF_RELE() on return.
*/
void
{
while (rdp) {
} else {
}
}
}
}
if (bytes) {
}
}
}
}
/*
* The reclaim is called by the kmem subsystem when kmem is running
* low. More work is needed to determine the best reclaim policy, for
* now we just manipulate the nl7c_uri_max global maximum bytes threshold
* value using a simple arithmetic backoff of the value every time this
* function is called then call uri_reclaim() to enforce it.
*
* Note, this value remains in place and enforced for all subsequent
*
* Note, nl7c_uri_max is currently initialized to 0 or infinite such that
* the first call here set it to the current uri_bytes value then backoff
* from there.
*
* XXX how do we determine when to increase nl7c_uri_max ???
*/
/*ARGSUSED*/
static void
{
if ((new_max = nl7c_uri_max) == 0) {
/* Currently infinite, initialize to current bytes used */
}
if (new_max > 1) {
/* Lower max_bytes to 93% of current value */
if (new_max < nl7c_uri_max)
else
nl7c_uri_max = 1;
}
}
/*
* Delete a uri_desc_t from the URI hash.
*/
static void
{
next:
continue;
}
/*
* Found the URI, unlink from the hash chain,
* drop locks, ref release it.
*/
return;
}
/*
* Not found in current hash and have a new hash so
* check the new hash next.
*/
goto next;
}
}
/*
* Add a uri_desc_t to the URI hash.
*/
static void
{
/*
* Caller of uri_add() must hold the uri_hash_access rwlock.
*/
/*
* uri_add() always succeeds so add a hash ref to the URI now.
*/
/*
* Easy case, no new hash and current hasn't overflowed,
* add URI to current hash and return.
*
* Note, the check for uri_hash_cnt[] above aren't done
* atomictally, i.e. multiple threads can be in this code
* as RW_READER and update the cnt[], this isn't a problem
* as the check is only advisory.
*/
fast:
return;
}
/*
* Need a new a or b hash, if not already RW_WRITER
* try to upgrade our lock to writer.
*/
/*
* Upgrade failed, we can't simple exit and reenter
* the lock as after the exit and before the reenter
* the whole world can change so just wait for writer
* then do everything again.
*/
if (nonblocking) {
/*
* Can't block, use fast-path above.
*
* XXX should have a background thread to
* handle new ab[] in this case so as to
* not overflow the cur hash to much.
*/
goto fast;
}
goto again;
}
/*
* Still need a new hash, allocate and initialize
* the new hash.
*/
if (uri_hash_n[new] == 0) {
/*
* No larger P2Ps[] value so use current,
* i.e. 2 of the largest are better than 1 ?
*/
}
KM_SLEEP);
/*
* Alloc failed, use fast-path above.
*
* XXX should have a background thread to
* handle new ab[] in this case so as to
* not overflow the cur hash to much.
*/
goto fast;
}
}
}
/*
* Hashed against current hash so migrate any current hash chain
* members, if any.
*
* Note, the hash chain list can be checked for a non empty list
* outside of the hash chain list lock as the hash chain struct
* can't be destroyed while in the uri_hash_access rwlock, worst
* case is that a non empty list is found and after acquiring the
* lock another thread beats us to it (i.e. migrated the list).
*/
}
/*
* If new hash has overflowed before current hash has been
* completely migrated then walk all current hash chains and
* migrate list members now.
*/
}
}
}
/*
* Add URI to new hash.
*/
/*
* Last, check to see if last cur hash chain has been
* migrated, if so free cur hash and make new hash cur.
*/
if (uri_hash_cnt[cur] == 0) {
/*
* If we don't already hold the uri_hash_access rwlock for
* RW_WRITE try to upgrade to RW_WRITE and if successful
* check again and to see if still need to do the free.
*/
}
}
}
/*
* Lookup a uri_desc_t in the URI hash, if found free the request uri_desc_t
* and return the found uri_desc_t with a REF_HOLD() placed on it. Else, if
* add B_TRUE use the request URI to create a new hash entry. Else if add
* B_FALSE ...
*/
static uri_desc_t *
{
char a, b;
/* Compare paths */
if ((a = *ap) == '%') {
/* Escaped hex multichar, convert it */
}
if ((b = *bp) == '%') {
/* Escaped hex multichar, convert it */
}
if (a != b) {
/* Char's don't match */
goto nexturi;
}
ap++;
bp++;
}
/* Not same length */
goto nexturi;
}
/* URI has auth request URI doesn't */
goto nexturi;
}
if ((a = *ap) == '%') {
/* Escaped hex multichar, convert it */
}
if ((b = *bp) == '%') {
/* Escaped hex multichar, convert it */
}
if (a != b) {
/* Char's don't match */
goto nexturi;
}
ap++;
bp++;
}
/* Not same length */
goto nexturi;
}
/* URI doesn't have auth and request URI does */
goto nexturi;
}
/*
* of requested URI, check for expire or request no cache
* purge.
*/
/*
* URI has expired or request specified to not use
* the cached version, unlink the URI from the hash
* chain, release all locks, release the hash ref
* on the URI, and last look it up again.
*
* Note, this will cause all variants of the named
* URI to be purged.
*/
} else {
}
else
goto again;
}
/*
* URI has scheme private qualifier(s), if request
* URI doesn't or if no match skip this URI.
*/
goto nexturi;
/*
* URI doesn't have scheme private qualifiers but
* request URI does, no match, skip this URI.
*/
goto nexturi;
}
/*
* Have a match, ready URI for return, first put a reference
* hold on the URI, if this URI is currently being processed
* then have to wait for the processing to be completed and
* redo the lookup, else return it.
*/
/* The URI is being processed, wait for completion */
if (! nonblocking &&
/*
* URI has been processed but things may
* have changed while we were away so do
* most everything again.
*/
goto again;
} else {
/*
* A nonblocking socket or an interrupted
* cv_wait_sig() in the first case can't
* block waiting for the processing of the
* uri hash hit uri to complete, in both
* cases just return failure to lookup.
*/
return (NULL);
}
}
return (uri);
}
/*
* Not found in current hash and have a new hash so
* check the new hash next.
*/
goto nexthash;
}
add:
if (! add) {
/* Lookup only so return failure */
return (NULL);
}
/*
* URI not hashed, finish intialization of the
* request URI, add it to the hash, return it.
*/
/* uri_add() has done rw_exit(&uri_hash_access) */
return (ruri);
}
/*
* Reclaim URIs until max cache size threshold has been reached.
*
* A CLOCK based reclaim modified with a history (hit counter) counter.
*/
static void
nl7c_uri_reclaim(void)
{
next:
while (nl7c_uri_bytes > nl7c_uri_max) {
/*
* Decrement URI activity counter and skip.
*/
continue;
}
/*
* Currently being processed by a socket, skip.
*/
continue;
}
/*
* Found a candidate, no hit(s) since added or last
* reclaim pass, unlink from it's hash chain, update
* lru scan pointer, drop lock, ref release it.
*/
if (cur == uri_hash_which) {
/* Wrap pointer */
}
}
goto again;
}
/* Wrap pointer */
}
/*
* Done with the current hash and have a
* new hash so check the new hash next.
*/
goto next;
}
}
}
}
/*
* Called for a socket which is being freed prior to close, e.g. errored.
*/
void
{
}
} else {
/* No proclock as uri exclusively owned by so */
}
}
/*
* ...
*
* < 0 need more data
*
* 0 parse complete
*
* > 0 parse error
*/
static int
{
/* Parse fail */
goto pfail;
}
/* More data */
goto pass;
}
/*
* After response parse now no cache,
* delete it from cache, wakeup any
* waiters on this URI, make URI_TEMP.
*/
}
}
/* More data needed */
return (-1);
}
/* Success */
return (0);
return (EINVAL);
pass:
return (ENOTSUP);
}
/*
* Called to sink application response data, the processing of the data
* is the same for a cached or temp URI (i.e. a URI for which we aren't
* going to cache the URI but want to parse it for detecting response
* data end such that for a persistent connection we can parse the next
* request).
*
* On return 0 is returned for sink success, > 0 on error, and < 0 on
* no so URI (note, data not sinked).
*/
int
{
int cnt;
char *bp;
/* Socket & NL7C out of sync, disable NL7C */
sti->sti_nl7c_flags = 0;
return (-1);
}
} else {
}
goto fail;
}
}
goto next;
}
if (error)
goto fail;
next:
uio->uio_iovcnt--;
}
/* Successfull sink of data, response parse the data */
/* Send the data out the connection */
if (error)
goto fail;
/* Success */
if (perror == 0 &&
/*
* No more data needed and no pending response
* data or current data count >= response length
* so close the URI processing for this so.
*/
nl7c_close(so);
/* Not a persistent connection */
sti->sti_nl7c_flags = 0;
}
}
return (0);
fail:
}
sti->sti_nl7c_flags = 0;
return (error);
}
/*
* Called to read data from file "*fp" at offset "*off" of length "*len"
* for a maximum of "*max_rem" bytes.
*
* On success a pointer to the kmem_alloc()ed file data is returned, "*off"
* and "*len" are updated for the acutal number of bytes read and "*max_rem"
* is updated with the number of bytes remaining to be read.
*
* Else, "NULL" is returned.
*/
static char *
{
int flg = 0;
char *data;
int error;
if (*off > MAXOFFSET_T) {
return (NULL);
}
if (error) {
return (NULL);
}
return (data);
}
/*
* Called to sink application response sendfilev, as with nl7c_data() above
* all the data will be processed by NL7C unless there's an error.
*/
int
{
int len;
int cnt;
int total_count = 0;
char *alloc;
int max;
int perror;
int error = 0;
/* Socket & NL7C out of sync, disable NL7C */
sti->sti_nl7c_flags = 0;
return (0);
}
while (sfvc-- > 0) {
/*
* off - the current sfv read file offset or user address.
*
* len - the current sfv length in bytes.
*
* cnt - number of bytes kmem_alloc()ed.
*
* alloc - the kmem_alloc()ed buffer of size "cnt".
*
* data - copy of "alloc" used for post alloc references.
*
* fp - the current sfv file_t pointer.
*
* vp - the current "*vp" vnode_t pointer.
*
* Note, for "data" and "fp" and "vp" a NULL value is used
* when not allocated such that the common failure path "fail"
* is used.
*/
if (len == 0) {
sfvp++;
continue;
}
/*
* User memory, copyin() all the bytes.
*/
if (error)
goto fail;
} else {
/*
* File descriptor, prefetch some bytes.
*/
goto fail;
}
goto fail;
}
goto fail;
}
/* Read max_rem bytes from file for prefetch */
if (nl7c_use_kmem) {
} else {
}
goto fail;
}
goto fail;
}
total_count += cnt;
}
/* Response parse */
/* Send kmem data out the connection */
if (error)
goto fail;
/*
* File descriptor, if any bytes left save vnode_t.
*/
/* More file data so add it */
goto fail;
}
/* Send vnode data out the connection */
} else {
/* All file data fit in the prefetch */
}
}
sfvp++;
if (first)
}
if (total_count > 0) {
}
if (perror == 0 &&
/*
* No more data needed and no pending response
* data or current data count >= response length
* so close the URI processing for this so.
*/
nl7c_close(so);
/* Not a persistent connection */
sti->sti_nl7c_flags = 0;
}
}
return (0);
fail:
if (total_count > 0) {
}
sti->sti_nl7c_flags = 0;
return (error);
}
/*
* Called for a socket which is closing or when an application has
* completed sending all the response data (i.e. for a persistent
* connection called once for each completed application response).
*/
void
{
/*
* No URI being processed so might be a listen()er
* if so do any cleanup, else nothing more to do.
*/
(void) nl7c_close_addr(so);
}
return;
}
}
} else {
/* No proclock as uri exclusively owned by so */
}
}
}
/*
* The uri_segmap_t ref_t inactive function called on the last REF_RELE(),
* release the segmap mapping. Note, the uri_segmap_t will be freed by
* REF_RELE() on return.
*/
void
{
if (!segmap_kpm) {
}
}
/*
* The call-back for desballoc()ed mblk_t's, if a segmap mapped mblk_t
* release the reference, one per desballoc() of a segmap page, if a rd_t
* mapped mblk_t release the reference, one per desballoc() of a uri_desc_t,
* last kmem free the uri_desb_t.
*/
static void
{
}
}
/*
* Segmap map up to a page of a uri_rd_t file descriptor.
*/
{
F_SOFTLOCK, S_READ) != 0) {
return (NULL);
}
return (segmap);
}
/*
* Chop up the kernel virtual memory area *data of size *sz bytes for
* a maximum of *bytes bytes into an besballoc()ed mblk_t chain using
* the given template uri_desb_t *temp of max_mblk bytes per.
*
* The values of *data, *sz, and *bytes are updated on return, the
* mblk_t chain is returned.
*/
static mblk_t *
char **data,
int *bytes,
int max_mblk,
char *eoh,
)
{
int msz;
return (NULL);
if (msz == 0) {
goto zero;
}
}
}
}
}
}
return (NULL);
}
zero:
} else {
}
}
}
if (bytes)
return (mp);
}
/*
* Experimential noqwait (i.e. no canput()/qwait() checks), just send
* the entire mblk_t chain down without flow-control checks.
*/
static int
{
int error = 0;
/* Fast check of flags before acquiring the lock */
if (error != 0) {
}
return (error);
}
}
return (0);
}
/*
* Send the URI uri_desc_t *uri response uri_rd_t *rdp out the socket_t *so.
*/
static int
{
int wsz;
int write_bytes;
char *segmap_data;
int error;
/* Initialize template uri_desb_t */
/* Get a local copy of the rd_t */
do {
if (first) {
/*
* For first kstrwrite() enough data to get
* things going, note non blocking version of
* kstrwrite() will be used below.
*/
} else {
ASSERT(write_bytes > 0);
}
/*
* Chop up to a write_bytes worth of data.
*/
wsz = write_bytes;
do {
break;
} else {
}
goto invalidate;
}
} else {
goto invalidate;
}
}
goto invalidate;
}
if (segmap_sz == 0) {
}
}
} else {
}
if (first) {
/* First kstrwrite(), use noqwait */
goto invalidate;
/*
* For the rest of the kstrwrite()s use SO_SNDBUF
* worth of data at a time, note these kstrwrite()s
* may (will) block one or more times.
*/
} else {
if ((error =
goto invalidate;
} else
goto invalidate;
}
}
return (0);
if (segmap) {
}
if (wmp)
return (error);
}
/*
* Send the URI uri_desc_t *uri response out the socket_t *so.
*/
static int
{
int error;
if (error != 0) {
goto invalidate;
}
}
return (0);
return (error);
}
/*
* The pchars[] array is indexed by a char to determine if it's a
* valid URI path component chararcter where:
*
* pchar = unreserved | escaped |
* ":" | "@" | "&" | "=" | "+" | "$" | ","
*
* unreserved = alphanum | mark
*
* alphanum = alpha | digit
*
* alpha = lowalpha | upalpha
*
* lowalpha = "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" |
* "i" | "j" | "k" | "l" | "m" | "n" | "o" | "p" |
* "q" | "r" | "s" | "t" | "u" | "v" | "w" | "x" |
* "y" | "z"
*
* upalpha = "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" |
* "I" | "J" | "K" | "L" | "M" | "N" | "O" | "P" |
* "Q" | "R" | "S" | "T" | "U" | "V" | "W" | "X" |
* "Y" | "Z"
*
* digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" |
* "8" | "9"
*
* mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")"
*
* escaped = "%" hex hex
* hex = digit | "A" | "B" | "C" | "D" | "E" | "F" |
* "a" | "b" | "c" | "d" | "e" | "f"
*/
static char pchars[] = {
0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 - 0x07 */
0, 0, 0, 0, 0, 0, 0, 0, /* 0x08 - 0x0F */
0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 - 0x17 */
0, 0, 0, 0, 0, 0, 0, 0, /* 0x18 - 0x1F */
0, 1, 0, 0, 1, 1, 1, 1, /* 0x20 - 0x27 */
0, 0, 1, 1, 1, 1, 1, 1, /* 0x28 - 0x2F */
1, 1, 1, 1, 1, 1, 1, 1, /* 0x30 - 0x37 */
1, 1, 1, 0, 0, 1, 0, 0, /* 0x38 - 0x3F */
1, 1, 1, 1, 1, 1, 1, 1, /* 0x40 - 0x47 */
1, 1, 1, 1, 1, 1, 1, 1, /* 0x48 - 0x4F */
1, 1, 1, 1, 1, 1, 1, 1, /* 0x50 - 0x57 */
1, 1, 1, 0, 0, 0, 0, 1, /* 0x58 - 0x5F */
0, 1, 1, 1, 1, 1, 1, 1, /* 0x60 - 0x67 */
1, 1, 1, 1, 1, 1, 1, 1, /* 0x68 - 0x6F */
1, 1, 1, 1, 1, 1, 1, 1, /* 0x70 - 0x77 */
1, 1, 1, 0, 0, 0, 1, 0 /* 0x78 - 0x7F */
};
/*
* This is the main L7 request message parse, we are called each time
* new data is availble for a socket, each time a single buffer of the
* entire message to date is given.
*
* Here we parse the request looking for the URI, parse it, and if a
* supported scheme call the scheme parser to commplete the parse of any
* headers which may further qualify the identity of the requested object
* then lookup it up in the URI hash.
*
* Return B_TRUE for more processing.
*
* Note, at this time the parser supports the generic message format as
* specified in RFC 822 with potentional limitations as specified in RFC
* 2616 for HTTP messages.
*
* Note, the caller supports an mblk_t chain, for now the parser(s)
* require the complete header in a single mblk_t. This is the common
* case and certainly for high performance environments, if at a future
* date mblk_t chains are important the parse can be reved to process
* mblk_t chains.
*/
{
char c;
char *uris;
goto pass;
}
/*
* Allocate and initialize minimumal state for the request
* uri_desc_t, in the cache hit case this uri_desc_t will
* be freed.
*/
/*
* Set request time to current time.
*/
/*
* Parse the Request-Line for the URI.
*
* For backwards HTTP version compatable reasons skip any leading
* CRLF (or CR or LF) line terminator(s) preceding Request-Line.
*/
cp++;
}
get++;
cp++;
}
if (*get != 0) {
/* Note a "GET", check for "POST" */
post++;
cp++;
}
if (*post != 0) {
goto more;
}
/* Not a "GET" or a "POST", just pass */
goto pass;
}
/* "POST", don't cache but still may want to parse */
}
/*
* Skip over URI path char(s) and save start and past end pointers.
*/
if (c == '?') {
/* Don't cache but still may want to parse */
}
cp++;
}
goto more;
}
/*
* Request-Line URI parsed, pass the rest of the request on
* to the the http scheme parse.
*/
/*
* Parse not successful or pass on request, the pointer
* to the parse pointer "cp" is overloaded such that ! NULL
* for more data and NULL for bad parse of request or pass.
*/
goto more;
}
goto pass;
}
}
/* Temporary URI so skip hash processing */
goto temp;
}
/* Not persistent so not interested in the response */
goto pass;
}
/*
* Check the URI hash for a cached response, save the request
* uri in case we need it below.
*/
/*
* Failed to lookup due to nonblocking wait required,
* interrupted cv_wait_sig(), KM_NOSLEEP memory alloc
* failure, ... Just pass on this request.
*/
goto pass;
}
/*
* We have the response cached, update recv mblk rptr
* to reflect the data consumed in parse.
*/
} else {
}
nl7c_uri_hit++;
/* If logging enabled log request */
if (nl7c_logd_enabled) {
/* Only support IPv4 addrs */
faddr = ((struct sockaddr_in *)
} else {
faddr = 0;
}
/* XXX need to pass response type, e.g. 200, 304 */
}
/* If conditional request check for substitute response */
if (ruri->conditional) {
}
/*
* Release reference on request URI, send the response out
* the socket, release reference on response uri, set the
* *ret value to B_TRUE to indicate request was consumed
* then return B_FALSE to indcate no more data needed.
*/
return (B_FALSE);
}
/*
* Miss the cache, the request URI is in the cache waiting for
* application write-side data to fill it.
*/
temp:
/*
* A miss or temp URI for which response data is needed, link
* uri to so and so to uri, set WAITWRITE in the so such that
* read-side processing is suspended (so the next read() gets
* the request data) until a write() is processed by NL7C.
*
* Note, sti->sti_nl7c_uri now owns the REF_INIT() ref.
*/
return (B_FALSE);
more:
/* More data is needed, note fragmented recv not supported */
pass:
/* Pass on this request */
}
if (uri) {
}
sti->sti_nl7c_flags = 0;
return (B_FALSE);
}