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