Blame WWW/Library/Implementation/HTAAUtil.c

Packit f574b8
/*
Packit f574b8
 * $LynxId: HTAAUtil.c,v 1.36 2016/11/24 15:29:50 tom Exp $
Packit f574b8
 *
Packit f574b8
 * MODULE							HTAAUtil.c
Packit f574b8
 *		COMMON PARTS OF ACCESS AUTHORIZATION MODULE
Packit f574b8
 *			FOR BOTH SERVER AND BROWSER
Packit f574b8
 *
Packit f574b8
 * IMPORTANT:
Packit f574b8
 *	Routines in this module use dynamic allocation, but free
Packit f574b8
 *	automatically all the memory reserved by them.
Packit f574b8
 *
Packit f574b8
 *	Therefore the caller never has to (and never should)
Packit f574b8
 *	free() any object returned by these functions.
Packit f574b8
 *
Packit f574b8
 *	Therefore also all the strings returned by this package
Packit f574b8
 *	are only valid until the next call to the same function
Packit f574b8
 *	is made.  This approach is selected, because of the nature
Packit f574b8
 *	of access authorization: no string returned by the package
Packit f574b8
 *	needs to be valid longer than until the next call.
Packit f574b8
 *
Packit f574b8
 *	This also makes it easy to plug the AA package in:
Packit f574b8
 *	you don't have to ponder whether to free() something
Packit f574b8
 *	here or is it done somewhere else (because it is always
Packit f574b8
 *	done somewhere else).
Packit f574b8
 *
Packit f574b8
 *	The strings that the package needs to store are copied
Packit f574b8
 *	so the original strings given as parameters to AA
Packit f574b8
 *	functions may be freed or modified with no side effects.
Packit f574b8
 *
Packit f574b8
 *	The AA package does not free() anything else than what
Packit f574b8
 *	it has itself allocated.
Packit f574b8
 *
Packit f574b8
 *	AA (Access Authorization) package means modules which
Packit f574b8
 *	names start with HTAA.
Packit f574b8
 *
Packit f574b8
 * AUTHORS:
Packit f574b8
 *	AL	Ari Luotonen	luotonen@dxcern.cern.ch
Packit f574b8
 *	MD	Mark Donszelmann    duns@vxdeop.cern.ch
Packit f574b8
 *
Packit f574b8
 * HISTORY:
Packit f574b8
 *	 8 Nov 93  MD	(VMS only) Added case insensitive comparison in HTAA_templateCaseMatch
Packit f574b8
 *
Packit f574b8
 *
Packit f574b8
 * BUGS:
Packit f574b8
 *
Packit f574b8
 *
Packit f574b8
 */
Packit f574b8
Packit f574b8
#include <HTUtils.h>
Packit f574b8
Packit f574b8
#include <HTAAUtil.h>		/* Implemented here     */
Packit f574b8
#include <HTAssoc.h>		/* Assoc list           */
Packit f574b8
#include <HTTCP.h>
Packit f574b8
#include <HTTP.h>
Packit f574b8
Packit f574b8
#include <LYStrings.h>
Packit f574b8
#include <LYUtils.h>
Packit f574b8
#include <LYLeaks.h>
Packit f574b8
Packit f574b8
/* PUBLIC						HTAAScheme_enum()
Packit f574b8
 *		TRANSLATE SCHEME NAME INTO
Packit f574b8
 *		A SCHEME ENUMERATION
Packit f574b8
 *
Packit f574b8
 * ON ENTRY:
Packit f574b8
 *	name		is a string representing the scheme name.
Packit f574b8
 *
Packit f574b8
 * ON EXIT:
Packit f574b8
 *	returns		the enumerated constant for that scheme.
Packit f574b8
 */
Packit f574b8
HTAAScheme HTAAScheme_enum(const char *name)
Packit f574b8
{
Packit f574b8
    char *upcased = NULL;
Packit f574b8
Packit f574b8
    if (!name)
Packit f574b8
	return HTAA_UNKNOWN;
Packit f574b8
Packit f574b8
    StrAllocCopy(upcased, name);
Packit f574b8
    LYUpperCase(upcased);
Packit f574b8
Packit f574b8
    if (!StrNCmp(upcased, "NONE", 4)) {
Packit f574b8
	FREE(upcased);
Packit f574b8
	return HTAA_NONE;
Packit f574b8
    } else if (!StrNCmp(upcased, "BASIC", 5)) {
Packit f574b8
	FREE(upcased);
Packit f574b8
	return HTAA_BASIC;
Packit f574b8
    } else if (!StrNCmp(upcased, "PUBKEY", 6)) {
Packit f574b8
	FREE(upcased);
Packit f574b8
	return HTAA_PUBKEY;
Packit f574b8
    } else if (!StrNCmp(upcased, "KERBEROSV4", 10)) {
Packit f574b8
	FREE(upcased);
Packit f574b8
	return HTAA_KERBEROS_V4;
Packit f574b8
    } else if (!StrNCmp(upcased, "KERBEROSV5", 10)) {
Packit f574b8
	FREE(upcased);
Packit f574b8
	return HTAA_KERBEROS_V5;
Packit f574b8
    } else {
Packit f574b8
	FREE(upcased);
Packit f574b8
	return HTAA_UNKNOWN;
Packit f574b8
    }
Packit f574b8
}
Packit f574b8
Packit f574b8
/* PUBLIC						HTAAScheme_name()
Packit f574b8
 *			GET THE NAME OF A GIVEN SCHEME
Packit f574b8
 * ON ENTRY:
Packit f574b8
 *	scheme		is one of the scheme enum values:
Packit f574b8
 *			HTAA_NONE, HTAA_BASIC, HTAA_PUBKEY, ...
Packit f574b8
 *
Packit f574b8
 * ON EXIT:
Packit f574b8
 *	returns		the name of the scheme, i.e.
Packit f574b8
 *			"None", "Basic", "Pubkey", ...
Packit f574b8
 */
Packit f574b8
const char *HTAAScheme_name(HTAAScheme scheme)
Packit f574b8
{
Packit f574b8
    switch (scheme) {
Packit f574b8
    case HTAA_NONE:
Packit f574b8
	return "None";
Packit f574b8
    case HTAA_BASIC:
Packit f574b8
	return "Basic";
Packit f574b8
    case HTAA_PUBKEY:
Packit f574b8
	return "Pubkey";
Packit f574b8
    case HTAA_KERBEROS_V4:
Packit f574b8
	return "KerberosV4";
Packit f574b8
    case HTAA_KERBEROS_V5:
Packit f574b8
	return "KerberosV5";
Packit f574b8
    case HTAA_UNKNOWN:
Packit f574b8
	return "UNKNOWN";
Packit f574b8
    default:
Packit f574b8
	return "THIS-IS-A-BUG";
Packit f574b8
    }
Packit f574b8
}
Packit f574b8
Packit f574b8
/* PUBLIC						    HTAAMethod_enum()
Packit f574b8
 *		TRANSLATE METHOD NAME INTO AN ENUMERATED VALUE
Packit f574b8
 * ON ENTRY:
Packit f574b8
 *	name		is the method name to translate.
Packit f574b8
 *
Packit f574b8
 * ON EXIT:
Packit f574b8
 *	returns		HTAAMethod enumerated value corresponding
Packit f574b8
 *			to the given name.
Packit f574b8
 */
Packit f574b8
HTAAMethod HTAAMethod_enum(const char *name)
Packit f574b8
{
Packit f574b8
    if (!name)
Packit f574b8
	return METHOD_UNKNOWN;
Packit f574b8
Packit f574b8
    if (0 == strcasecomp(name, "GET"))
Packit f574b8
	return METHOD_GET;
Packit f574b8
    else if (0 == strcasecomp(name, "PUT"))
Packit f574b8
	return METHOD_PUT;
Packit f574b8
    else
Packit f574b8
	return METHOD_UNKNOWN;
Packit f574b8
}
Packit f574b8
Packit f574b8
/* PUBLIC						HTAAMethod_name()
Packit f574b8
 *			GET THE NAME OF A GIVEN METHOD
Packit f574b8
 * ON ENTRY:
Packit f574b8
 *	method		is one of the method enum values:
Packit f574b8
 *			METHOD_GET, METHOD_PUT, ...
Packit f574b8
 *
Packit f574b8
 * ON EXIT:
Packit f574b8
 *	returns		the name of the scheme, i.e.
Packit f574b8
 *			"GET", "PUT", ...
Packit f574b8
 */
Packit f574b8
const char *HTAAMethod_name(HTAAMethod method)
Packit f574b8
{
Packit f574b8
    switch (method) {
Packit f574b8
    case METHOD_GET:
Packit f574b8
	return "GET";
Packit f574b8
    case METHOD_PUT:
Packit f574b8
	return "PUT";
Packit f574b8
    case METHOD_UNKNOWN:
Packit f574b8
	return "UNKNOWN";
Packit f574b8
    default:
Packit f574b8
	return "THIS-IS-A-BUG";
Packit f574b8
    }
Packit f574b8
}
Packit f574b8
Packit f574b8
/* PUBLIC						HTAAMethod_inList()
Packit f574b8
 *		IS A METHOD IN A LIST OF METHOD NAMES
Packit f574b8
 * ON ENTRY:
Packit f574b8
 *	method		is the method to look for.
Packit f574b8
 *	list		is a list of method names.
Packit f574b8
 *
Packit f574b8
 * ON EXIT:
Packit f574b8
 *	returns		YES, if method was found.
Packit f574b8
 *			NO, if not found.
Packit f574b8
 */
Packit f574b8
BOOL HTAAMethod_inList(HTAAMethod method, HTList *list)
Packit f574b8
{
Packit f574b8
    HTList *cur = list;
Packit f574b8
    char *item;
Packit f574b8
Packit f574b8
    while (NULL != (item = (char *) HTList_nextObject(cur))) {
Packit f574b8
	CTRACE((tfp, " %s", item));
Packit f574b8
	if (method == HTAAMethod_enum(item))
Packit f574b8
	    return YES;
Packit f574b8
    }
Packit f574b8
Packit f574b8
    return NO;			/* Not found */
Packit f574b8
}
Packit f574b8
Packit f574b8
/* PUBLIC						HTAA_templateMatch()
Packit f574b8
 *		STRING COMPARISON FUNCTION FOR FILE NAMES
Packit f574b8
 *		   WITH ONE WILDCARD * IN THE TEMPLATE
Packit f574b8
 * NOTE:
Packit f574b8
 *	This is essentially the same code as in HTRules.c, but it
Packit f574b8
 *	cannot be used because it is embedded in between other code.
Packit f574b8
 *	(In fact, HTRules.c should use this routine, but then this
Packit f574b8
 *	 routine would have to be more sophisticated... why is life
Packit f574b8
 *	 sometimes so hard...)
Packit f574b8
 *
Packit f574b8
 * ON ENTRY:
Packit f574b8
 *	ctemplate	is a template string to match the file name
Packit f574b8
 *			against, may contain a single wildcard
Packit f574b8
 *			character * which matches zero or more
Packit f574b8
 *			arbitrary characters.
Packit f574b8
 *	filename	is the filename (or pathname) to be matched
Packit f574b8
 *			against the template.
Packit f574b8
 *
Packit f574b8
 * ON EXIT:
Packit f574b8
 *	returns		YES, if filename matches the template.
Packit f574b8
 *			NO, otherwise.
Packit f574b8
 */
Packit f574b8
BOOL HTAA_templateMatch(const char *ctemplate,
Packit f574b8
			const char *filename)
Packit f574b8
{
Packit f574b8
    const char *p = ctemplate;
Packit f574b8
    const char *q = filename;
Packit f574b8
    int m;
Packit f574b8
Packit f574b8
    for (; *p && *q && *p == *q; p++, q++)	/* Find first mismatch */
Packit f574b8
	;			/* do nothing else */
Packit f574b8
Packit f574b8
    if (!*p && !*q)
Packit f574b8
	return YES;		/* Equally long equal strings */
Packit f574b8
    else if ('*' == *p) {	/* Wildcard */
Packit f574b8
	p++;			/* Skip wildcard character */
Packit f574b8
	m = (int) (strlen(q) - strlen(p));	/* Amount to match to wildcard */
Packit f574b8
	if (m < 0)
Packit f574b8
	    return NO;		/* No match, filename too short */
Packit f574b8
	else {			/* Skip the matched characters and compare */
Packit f574b8
	    if (strcmp(p, q + m))
Packit f574b8
		return NO;	/* Tail mismatch */
Packit f574b8
	    else
Packit f574b8
		return YES;	/* Tail match */
Packit f574b8
	}
Packit f574b8
	/* if wildcard */
Packit f574b8
    } else
Packit f574b8
	return NO;		/* Length or character mismatch */
Packit f574b8
}
Packit f574b8
Packit f574b8
/* PUBLIC						HTAA_templateCaseMatch()
Packit f574b8
 *		STRING COMPARISON FUNCTION FOR FILE NAMES
Packit f574b8
 *		   WITH ONE WILDCARD * IN THE TEMPLATE (Case Insensitive)
Packit f574b8
 * NOTE:
Packit f574b8
 *	This is essentially the same code as in HTAA_templateMatch, but
Packit f574b8
 *	it compares case insensitive (for VMS). Reason for this routine
Packit f574b8
 *	is that HTAA_templateMatch gets called from several places, also
Packit f574b8
 *	there where a case sensitive match is needed, so one cannot just
Packit f574b8
 *	change the HTAA_templateMatch routine for VMS.
Packit f574b8
 *
Packit f574b8
 * ON ENTRY:
Packit f574b8
 *	template	is a template string to match the file name
Packit f574b8
 *			against, may contain a single wildcard
Packit f574b8
 *			character * which matches zero or more
Packit f574b8
 *			arbitrary characters.
Packit f574b8
 *	filename	is the filename (or pathname) to be matched
Packit f574b8
 *			against the template.
Packit f574b8
 *
Packit f574b8
 * ON EXIT:
Packit f574b8
 *	returns		YES, if filename matches the template.
Packit f574b8
 *			NO, otherwise.
Packit f574b8
 */
Packit f574b8
BOOL HTAA_templateCaseMatch(const char *ctemplate,
Packit f574b8
			    const char *filename)
Packit f574b8
{
Packit f574b8
    const char *p = ctemplate;
Packit f574b8
    const char *q = filename;
Packit f574b8
    int m;
Packit f574b8
Packit f574b8
    /* Find first mismatch */
Packit f574b8
    for (; *p && *q && TOUPPER(*p) == TOUPPER(*q); p++, q++) ;	/* do nothing else */
Packit f574b8
Packit f574b8
    if (!*p && !*q)
Packit f574b8
	return YES;		/* Equally long equal strings */
Packit f574b8
    else if ('*' == *p) {	/* Wildcard */
Packit f574b8
	p++;			/* Skip wildcard character */
Packit f574b8
	m = (int) (strlen(q) - strlen(p));	/* Amount to match to wildcard */
Packit f574b8
	if (m < 0)
Packit f574b8
	    return NO;		/* No match, filename too short */
Packit f574b8
	else {			/* Skip the matched characters and compare */
Packit f574b8
	    if (strcasecomp(p, q + m))
Packit f574b8
		return NO;	/* Tail mismatch */
Packit f574b8
	    else
Packit f574b8
		return YES;	/* Tail match */
Packit f574b8
	}
Packit f574b8
	/* if wildcard */
Packit f574b8
    } else
Packit f574b8
	return NO;		/* Length or character mismatch */
Packit f574b8
}
Packit f574b8
Packit f574b8
/* PUBLIC					HTAA_makeProtectionTemplate()
Packit f574b8
 *		CREATE A PROTECTION TEMPLATE FOR THE FILES
Packit f574b8
 *		IN THE SAME DIRECTORY AS THE GIVEN FILE
Packit f574b8
 *		(Used by server if there is no fancier way for
Packit f574b8
 *		it to tell the client, and by browser if server
Packit f574b8
 *		didn't send WWW-ProtectionTemplate: field)
Packit f574b8
 * ON ENTRY:
Packit f574b8
 *	docname is the document pathname (from URL).
Packit f574b8
 *
Packit f574b8
 * ON EXIT:
Packit f574b8
 *	returns a template matching docname, and other files
Packit f574b8
 *		files in that directory.
Packit f574b8
 *
Packit f574b8
 *		E.g.  /foo/bar/x.html  =>  /foo/bar/ *
Packit f574b8
 *						    ^
Packit f574b8
 *				Space only to prevent it from
Packit f574b8
 *				being a comment marker here,
Packit f574b8
 *				there really isn't any space.
Packit f574b8
 */
Packit f574b8
char *HTAA_makeProtectionTemplate(const char *docname)
Packit f574b8
{
Packit f574b8
    char *ctemplate = NULL;
Packit f574b8
    char *slash = NULL;
Packit f574b8
Packit f574b8
    if (docname) {
Packit f574b8
	StrAllocCopy(ctemplate, docname);
Packit f574b8
	slash = strrchr(ctemplate, '/');
Packit f574b8
	if (slash)
Packit f574b8
	    slash++;
Packit f574b8
	else
Packit f574b8
	    slash = ctemplate;
Packit f574b8
	*slash = '\0';
Packit f574b8
	StrAllocCat(ctemplate, "*");
Packit f574b8
    } else
Packit f574b8
	StrAllocCopy(ctemplate, "*");
Packit f574b8
Packit f574b8
    CTRACE((tfp, "make_template: made template `%s' for file `%s'\n",
Packit f574b8
	    ctemplate, docname));
Packit f574b8
Packit f574b8
    return ctemplate;
Packit f574b8
}
Packit f574b8
Packit f574b8
/*
Packit f574b8
 * Skip leading whitespace from *s forward
Packit f574b8
 */
Packit f574b8
#define SKIPWS(s) while (*s==' ' || *s=='\t') s++;
Packit f574b8
Packit f574b8
/*
Packit f574b8
 * Kill trailing whitespace starting from *(s-1) backwards
Packit f574b8
 */
Packit f574b8
#define KILLWS(s) {char *c=s-1; while (*c==' ' || *c=='\t') *(c--)='\0';}
Packit f574b8
Packit f574b8
/* PUBLIC						HTAA_parseArgList()
Packit f574b8
 *		PARSE AN ARGUMENT LIST GIVEN IN A HEADER FIELD
Packit f574b8
 * ON ENTRY:
Packit f574b8
 *	str	is a comma-separated list:
Packit f574b8
 *
Packit f574b8
 *			item, item, item
Packit f574b8
 *		where
Packit f574b8
 *			item ::= value
Packit f574b8
 *			       | name=value
Packit f574b8
 *			       | name="value"
Packit f574b8
 *
Packit f574b8
 *		Leading and trailing whitespace is ignored
Packit f574b8
 *		everywhere except inside quotes, so the following
Packit f574b8
 *		examples are equal:
Packit f574b8
 *
Packit f574b8
 *			name=value,foo=bar
Packit f574b8
 *			 name="value",foo="bar"
Packit f574b8
 *			  name = value ,  foo = bar
Packit f574b8
 *			   name = "value" ,  foo = "bar"
Packit f574b8
 *
Packit f574b8
 * ON EXIT:
Packit f574b8
 *	returns a list of name-value pairs (actually HTAssocList*).
Packit f574b8
 *		For items with no name, just value, the name is
Packit f574b8
 *		the number of order number of that item. E.g.
Packit f574b8
 *		"1" for the first, etc.
Packit f574b8
 */
Packit f574b8
HTAssocList *HTAA_parseArgList(char *str)
Packit f574b8
{
Packit f574b8
    HTAssocList *assoc_list = HTAssocList_new();
Packit f574b8
    char *cur = NULL;
Packit f574b8
    char *name = NULL;
Packit f574b8
    int n = 0;
Packit f574b8
Packit f574b8
    if (!str)
Packit f574b8
	return assoc_list;
Packit f574b8
Packit f574b8
    while (*str) {
Packit f574b8
	SKIPWS(str);		/* Skip leading whitespace */
Packit f574b8
	cur = str;
Packit f574b8
	n++;
Packit f574b8
Packit f574b8
	while (*cur && *cur != '=' && *cur != ',')
Packit f574b8
	    cur++;		/* Find end of name (or lonely value without a name) */
Packit f574b8
	KILLWS(cur);		/* Kill trailing whitespace */
Packit f574b8
Packit f574b8
	if (*cur == '=') {	/* Name followed by a value */
Packit f574b8
	    *(cur++) = '\0';	/* Terminate name */
Packit f574b8
	    StrAllocCopy(name, str);
Packit f574b8
	    SKIPWS(cur);	/* Skip WS leading the value */
Packit f574b8
	    str = cur;
Packit f574b8
	    if (*str == '"') {	/* Quoted value */
Packit f574b8
		str++;
Packit f574b8
		cur = str;
Packit f574b8
		while (*cur && *cur != '"')
Packit f574b8
		    cur++;
Packit f574b8
		if (*cur == '"')
Packit f574b8
		    *(cur++) = '\0';	/* Terminate value */
Packit f574b8
		/* else it is lacking terminating quote */
Packit f574b8
		SKIPWS(cur);	/* Skip WS leading comma */
Packit f574b8
		if (*cur == ',')
Packit f574b8
		    cur++;	/* Skip separating colon */
Packit f574b8
	    } else {		/* Unquoted value */
Packit f574b8
		while (*cur && *cur != ',')
Packit f574b8
		    cur++;
Packit f574b8
		KILLWS(cur);	/* Kill trailing whitespace */
Packit f574b8
		if (*cur == ',')
Packit f574b8
		    *(cur++) = '\0';
Packit f574b8
		/* else *cur already NULL */
Packit f574b8
	    }
Packit f574b8
	} else {		/* No name, just a value */
Packit f574b8
	    if (*cur == ',')
Packit f574b8
		*(cur++) = '\0';	/* Terminate value */
Packit f574b8
	    /* else last value on line (already terminated by NULL) */
Packit f574b8
	    HTSprintf0(&name, "%d", n);		/* Item order number for name */
Packit f574b8
	}
Packit f574b8
	HTAssocList_add(assoc_list, name, str);
Packit f574b8
	str = cur;
Packit f574b8
    }				/* while *str */
Packit f574b8
Packit f574b8
    FREE(name);
Packit f574b8
    return assoc_list;
Packit f574b8
}
Packit f574b8
Packit f574b8
/************** HEADER LINE READER -- DOES UNFOLDING *************************/
Packit f574b8
Packit f574b8
#define BUFFER_SIZE	1024
Packit f574b8
Packit f574b8
static size_t buffer_length;
Packit f574b8
static char *buffer = 0;
Packit f574b8
static char *start_pointer;
Packit f574b8
static char *end_pointer;
Packit f574b8
static int in_soc = -1;
Packit f574b8
Packit f574b8
#ifdef LY_FIND_LEAKS
Packit f574b8
static void FreeHTAAUtil(void)
Packit f574b8
{
Packit f574b8
    FREE(buffer);
Packit f574b8
}
Packit f574b8
#endif /* LY_FIND_LEAKS */
Packit f574b8
Packit f574b8
/* PUBLIC						HTAA_setupReader()
Packit f574b8
 *		SET UP HEADER LINE READER, i.e., give
Packit f574b8
 *		the already-read-but-not-yet-processed
Packit f574b8
 *		buffer of text to be read before more
Packit f574b8
 *		is read from the socket.
Packit f574b8
 * ON ENTRY:
Packit f574b8
 *	start_of_headers is a pointer to a buffer containing
Packit f574b8
 *			the beginning of the header lines
Packit f574b8
 *			(rest will be read from a socket).
Packit f574b8
 *	length		is the number of valid characters in
Packit f574b8
 *			'start_of_headers' buffer.
Packit f574b8
 *	soc		is the socket to use when start_of_headers
Packit f574b8
 *			buffer is used up.
Packit f574b8
 * ON EXIT:
Packit f574b8
 *	returns		nothing.
Packit f574b8
 *			Subsequent calls to HTAA_getUnfoldedLine()
Packit f574b8
 *			will use this buffer first and then
Packit f574b8
 *			proceed to read from socket.
Packit f574b8
 */
Packit f574b8
void HTAA_setupReader(char *start_of_headers,
Packit f574b8
		      size_t length,
Packit f574b8
		      int soc)
Packit f574b8
{
Packit f574b8
    if (!start_of_headers)
Packit f574b8
	length = 0;		/* initialize length (is this reached at all?) */
Packit f574b8
    if (buffer == NULL) {	/* first call? */
Packit f574b8
	buffer_length = length;
Packit f574b8
	if (buffer_length < BUFFER_SIZE)	/* would fall below BUFFER_SIZE? */
Packit f574b8
	    buffer_length = BUFFER_SIZE;
Packit f574b8
	buffer = (char *) malloc((size_t) (sizeof(char) * (buffer_length + 1)));
Packit f574b8
    } else if (length > buffer_length) {	/* need more space? */
Packit f574b8
	buffer_length = length;
Packit f574b8
	buffer = (char *) realloc((char *) buffer,
Packit f574b8
				  (size_t) (sizeof(char) * (buffer_length + 1)));
Packit f574b8
    }
Packit f574b8
    if (buffer == NULL)
Packit f574b8
	outofmem(__FILE__, "HTAA_setupReader");
Packit f574b8
Packit f574b8
#ifdef LY_FIND_LEAKS
Packit f574b8
    atexit(FreeHTAAUtil);
Packit f574b8
#endif
Packit f574b8
    start_pointer = buffer;
Packit f574b8
    if (start_of_headers) {
Packit f574b8
	LYStrNCpy(buffer, start_of_headers, length);
Packit f574b8
	end_pointer = buffer + length;
Packit f574b8
    } else {
Packit f574b8
	*start_pointer = '\0';
Packit f574b8
	end_pointer = start_pointer;
Packit f574b8
    }
Packit f574b8
    in_soc = soc;
Packit f574b8
}
Packit f574b8
Packit f574b8
/* PUBLIC						HTAA_getUnfoldedLine()
Packit f574b8
 *		READ AN UNFOLDED HEADER LINE FROM SOCKET
Packit f574b8
 * ON ENTRY:
Packit f574b8
 *	HTAA_setupReader must absolutely be called before
Packit f574b8
 *	this function to set up internal buffer.
Packit f574b8
 *
Packit f574b8
 * ON EXIT:
Packit f574b8
 *	returns a newly-allocated character string representing
Packit f574b8
 *		the read line.	The line is unfolded, i.e.
Packit f574b8
 *		lines that begin with whitespace are appended
Packit f574b8
 *		to current line.  E.g.
Packit f574b8
 *
Packit f574b8
 *			Field-Name: Blaa-Blaa
Packit f574b8
 *			 This-Is-A-Continuation-Line
Packit f574b8
 *			 Here-Is_Another
Packit f574b8
 *
Packit f574b8
 *		is seen by the caller as:
Packit f574b8
 *
Packit f574b8
 *	Field-Name: Blaa-Blaa This-Is-A-Continuation-Line Here-Is_Another
Packit f574b8
 *
Packit f574b8
 */
Packit f574b8
char *HTAA_getUnfoldedLine(void)
Packit f574b8
{
Packit f574b8
    char *line = NULL;
Packit f574b8
    char *cur;
Packit f574b8
    int count;
Packit f574b8
    BOOL peek_for_folding = NO;
Packit f574b8
Packit f574b8
    if (in_soc < 0) {
Packit f574b8
	CTRACE((tfp, "%s %s\n",
Packit f574b8
		"HTAA_getUnfoldedLine: buffer not initialized",
Packit f574b8
		"with function HTAA_setupReader()"));
Packit f574b8
	return NULL;
Packit f574b8
    }
Packit f574b8
Packit f574b8
    for (;;) {
Packit f574b8
Packit f574b8
	/* Reading from socket */
Packit f574b8
Packit f574b8
	if (start_pointer >= end_pointer) {	/*Read the next block and continue */
Packit f574b8
#ifdef USE_SSL
Packit f574b8
	    if (SSL_handle)
Packit f574b8
		count = SSL_read(SSL_handle, buffer, BUFFER_SIZE);
Packit f574b8
	    else
Packit f574b8
		count = NETREAD(in_soc, buffer, BUFFER_SIZE);
Packit f574b8
#else
Packit f574b8
	    count = NETREAD(in_soc, buffer, BUFFER_SIZE);
Packit f574b8
#endif /* USE_SSL */
Packit f574b8
	    if (count <= 0) {
Packit f574b8
		in_soc = -1;
Packit f574b8
		return line;
Packit f574b8
	    }
Packit f574b8
	    if (count > (int) buffer_length)
Packit f574b8
		count = (int) buffer_length;
Packit f574b8
	    start_pointer = buffer;
Packit f574b8
	    end_pointer = buffer + count;
Packit f574b8
	    *end_pointer = '\0';
Packit f574b8
#ifdef NOT_ASCII
Packit f574b8
	    cur = start_pointer;
Packit f574b8
	    while (cur < end_pointer) {
Packit f574b8
		*cur = TOASCII(*cur);
Packit f574b8
		cur++;
Packit f574b8
	    }
Packit f574b8
#endif /*NOT_ASCII */
Packit f574b8
	}
Packit f574b8
	cur = start_pointer;
Packit f574b8
Packit f574b8
	/* Unfolding */
Packit f574b8
Packit f574b8
	if (peek_for_folding) {
Packit f574b8
	    if (*cur != ' ' && *cur != '\t')
Packit f574b8
		return line;	/* Ok, no continuation line */
Packit f574b8
	    else		/* So this is a continuation line, continue */
Packit f574b8
		peek_for_folding = NO;
Packit f574b8
	}
Packit f574b8
Packit f574b8
	/* Finding end-of-line */
Packit f574b8
Packit f574b8
	while (cur < end_pointer && *cur != '\n')	/* Find the end-of-line */
Packit f574b8
	    cur++;		/* (or end-of-buffer).  */
Packit f574b8
Packit f574b8
	/* Terminating line */
Packit f574b8
Packit f574b8
	if (cur < end_pointer) {	/* So *cur==LF, terminate line */
Packit f574b8
	    *cur = '\0';	/* Overwrite LF */
Packit f574b8
	    if (*(cur - 1) == '\r')
Packit f574b8
		*(cur - 1) = '\0';	/* Overwrite CR */
Packit f574b8
	    peek_for_folding = YES;	/* Check for a continuation line */
Packit f574b8
	}
Packit f574b8
Packit f574b8
	/* Copying the result */
Packit f574b8
Packit f574b8
	if (line)
Packit f574b8
	    StrAllocCat(line, start_pointer);	/* Append */
Packit f574b8
	else
Packit f574b8
	    StrAllocCopy(line, start_pointer);	/* A new line */
Packit f574b8
Packit f574b8
	start_pointer = cur + 1;	/* Skip the read line */
Packit f574b8
Packit f574b8
    }				/* forever */
Packit f574b8
}