Annotation of libwww/Library/src/HTAAUtil.c, revision 2.1
2.1 ! luotonen 1:
! 2: /* MODULE HTAABoth.c
! 3: ** COMMON PARTS OF ACCESS AUTHORIZATION MODULE
! 4: ** FOR BOTH SERVER AND BROWSER
! 5: **
! 6: ** IMPORTANT:
! 7: ** Routines in this module use dynamic allocation, but free
! 8: ** automatically all the memory reserved by them.
! 9: **
! 10: ** Therefore the caller never has to (and never should)
! 11: ** free() any object returned by these functions.
! 12: **
! 13: ** Therefore also all the strings returned by this package
! 14: ** are only valid until the next call to the same function
! 15: ** is made. This approach is selected, because of the nature
! 16: ** of access authorization: no string returned by the package
! 17: ** needs to be valid longer than until the next call.
! 18: **
! 19: ** This also makes it easy to plug the AA package in:
! 20: ** you don't have to ponder whether to free() something
! 21: ** here or is it done somewhere else (because it is always
! 22: ** done somewhere else).
! 23: **
! 24: ** The strings that the package needs to store are copied
! 25: ** so the original strings given as parameters to AA
! 26: ** functions may be freed or modified with no side effects.
! 27: **
! 28: ** The AA package does not free() anything else than what
! 29: ** it has itself allocated.
! 30: **
! 31: ** AA (Access Authorization) package means modules which
! 32: ** names start with HTAA.
! 33: **
! 34: ** AUTHORS:
! 35: ** AL Ari Luotonen luotonen@dxcern.cern.ch
! 36: **
! 37: ** HISTORY:
! 38: **
! 39: **
! 40: ** BUGS:
! 41: **
! 42: **
! 43: */
! 44:
! 45: #include <string.h>
! 46: #include "HTUtils.h"
! 47: #include "tcp.h" /* NETREAD() etc. */
! 48: #include "HTAAUtil.h" /* Implemented here */
! 49: #include "HTAssoc.h" /* Assoc list */
! 50:
! 51:
! 52: /* PUBLIC HTAAScheme_enum()
! 53: ** TRANSLATE SCHEME NAME INTO
! 54: ** A SCHEME ENUMERATION
! 55: **
! 56: ** ON ENTRY:
! 57: ** name is a string representing the scheme name.
! 58: **
! 59: ** ON EXIT:
! 60: ** returns the enumerated constant for that scheme.
! 61: */
! 62: PUBLIC HTAAScheme HTAAScheme_enum ARGS1(CONST char*, name)
! 63: {
! 64: static char *upcased = NULL;
! 65: char *cur;
! 66:
! 67: if (!name) return HTAA_UNKNOWN;
! 68:
! 69: StrAllocCopy(upcased, name);
! 70: cur = upcased;
! 71: while (*cur) {
! 72: *cur = TOUPPER(*cur);
! 73: cur++;
! 74: }
! 75:
! 76: if (!strncmp(upcased, "NONE", 4))
! 77: return HTAA_NONE;
! 78: else if (!strncmp(upcased, "BASIC", 5))
! 79: return HTAA_BASIC;
! 80: else if (!strncmp(upcased, "PUBKEY", 6))
! 81: return HTAA_PUBKEY;
! 82: else if (!strncmp(upcased, "KERBEROSV4", 10))
! 83: return HTAA_KERBEROS_V4;
! 84: else if (!strncmp(upcased, "KERBEROSV5", 10))
! 85: return HTAA_KERBEROS_V5;
! 86: else
! 87: return HTAA_UNKNOWN;
! 88: }
! 89:
! 90:
! 91: /* PUBLIC HTAAScheme_name()
! 92: ** GET THE NAME OF A GIVEN SCHEME
! 93: ** ON ENTRY:
! 94: ** scheme is one of the scheme enum values:
! 95: ** HTAA_NONE, HTAA_BASIC, HTAA_PUBKEY, ...
! 96: **
! 97: ** ON EXIT:
! 98: ** returns the name of the scheme, i.e.
! 99: ** "None", "Basic", "Pubkey", ...
! 100: */
! 101: PUBLIC char *HTAAScheme_name ARGS1(HTAAScheme, scheme)
! 102: {
! 103: switch (scheme) {
! 104: case HTAA_NONE: return "None"; break;
! 105: case HTAA_BASIC: return "Basic"; break;
! 106: case HTAA_PUBKEY: return "Pubkey"; break;
! 107: case HTAA_KERBEROS_V4: return "KerberosV4"; break;
! 108: case HTAA_KERBEROS_V5: return "KerberosV5"; break;
! 109: case HTAA_UNKNOWN: return "UNKNOWN"; break;
! 110: default: return "THIS-IS-A-BUG";
! 111: }
! 112: }
! 113:
! 114:
! 115: /* PUBLIC HTAAMethod_enum()
! 116: ** TRANSLATE METHOD NAME INTO AN ENUMERATED VALUE
! 117: ** ON ENTRY:
! 118: ** name is the method name to translate.
! 119: **
! 120: ** ON EXIT:
! 121: ** returns HTAAMethod enumerated value corresponding
! 122: ** to the given name.
! 123: */
! 124: PUBLIC HTAAMethod HTAAMethod_enum ARGS1(CONST char *, name)
! 125: {
! 126: char tmp[MAX_METHODNAME_LEN+1];
! 127: CONST char *src = name;
! 128: char *dest = tmp;
! 129:
! 130: if (!name) return METHOD_UNKNOWN;
! 131:
! 132: while (*src) {
! 133: *dest = TOUPPER(*src);
! 134: dest++;
! 135: src++;
! 136: }
! 137: *dest = 0;
! 138:
! 139: if (0==strcmp(tmp, "GET"))
! 140: return METHOD_GET;
! 141: else if (0==strcmp(tmp, "PUT"))
! 142: return METHOD_PUT;
! 143: else
! 144: return METHOD_UNKNOWN;
! 145: }
! 146:
! 147:
! 148: /* PUBLIC HTAAMethod_name()
! 149: ** GET THE NAME OF A GIVEN METHOD
! 150: ** ON ENTRY:
! 151: ** method is one of the method enum values:
! 152: ** METHOD_GET, METHOD_PUT, ...
! 153: **
! 154: ** ON EXIT:
! 155: ** returns the name of the scheme, i.e.
! 156: ** "GET", "PUT", ...
! 157: */
! 158: PUBLIC char *HTAAMethod_name ARGS1(HTAAMethod, method)
! 159: {
! 160: switch (method) {
! 161: case METHOD_GET: return "GET"; break;
! 162: case METHOD_PUT: return "PUT"; break;
! 163: case METHOD_UNKNOWN: return "UNKNOWN"; break;
! 164: default: return "THIS-IS-A-BUG";
! 165: }
! 166: }
! 167:
! 168:
! 169: /* PUBLIC HTAAMethod_inList()
! 170: ** IS A METHOD IN A LIST OF METHOD NAMES
! 171: ** ON ENTRY:
! 172: ** method is the method to look for.
! 173: ** list is a list of method names.
! 174: **
! 175: ** ON EXIT:
! 176: ** returns YES, if method was found.
! 177: ** NO, if not found.
! 178: */
! 179: PUBLIC BOOL HTAAMethod_inList ARGS2(HTAAMethod, method,
! 180: HTList *, list)
! 181: {
! 182: HTList *cur = list;
! 183: char *item;
! 184:
! 185: while (NULL != (item = (char*)HTList_nextObject(cur))) {
! 186: if (TRACE) fprintf(stderr, " %s", item);
! 187: if (method == HTAAMethod_enum(item))
! 188: return YES;
! 189: }
! 190:
! 191: return NO; /* Not found */
! 192: }
! 193:
! 194:
! 195:
! 196: /* PUBLIC HTAA_templateMatch()
! 197: ** STRING COMPARISON FUNCTION FOR FILE NAMES
! 198: ** WITH ONE WILDCARD * IN THE TEMPLATE
! 199: ** NOTE:
! 200: ** This is essentially the same code as in HTRules.c, but it
! 201: ** cannot be used because it is embedded in between other code.
! 202: ** (In fact, HTRules.c should use this routine, but then this
! 203: ** routine would have to be more sophisticated... why is life
! 204: ** sometimes so hard...)
! 205: **
! 206: ** ON ENTRY:
! 207: ** template is a template string to match the file name
! 208: ** agaist, may contain a single wildcard
! 209: ** character * which matches zero or more
! 210: ** arbitrary characters.
! 211: ** filename is the filename (or pathname) to be matched
! 212: ** agaist the template.
! 213: **
! 214: ** ON EXIT:
! 215: ** returns YES, if filename matches the template.
! 216: ** NO, otherwise.
! 217: */
! 218: PUBLIC BOOL HTAA_templateMatch ARGS2(CONST char *, template,
! 219: CONST char *, filename)
! 220: {
! 221: CONST char *p = template;
! 222: CONST char *q = filename;
! 223: int m;
! 224:
! 225: for( ; *p && *q && *p == *q; p++, q++) /* Find first mismatch */
! 226: ; /* do nothing else */
! 227:
! 228: if (!*p && !*q) return YES; /* Equally long equal strings */
! 229: else if ('*' == *p) { /* Wildcard */
! 230: p++; /* Skip wildcard character */
! 231: m = strlen(q) - strlen(p); /* Amount to match to wildcard */
! 232: if (m < 0) return NO; /* No match, filename too short */
! 233: else { /* Skip the matched characters and compare */
! 234: if (strcmp(p, q+m)) return NO; /* Tail mismatch */
! 235: else return YES; /* Tail match */
! 236: }
! 237: } /* if wildcard */
! 238: else return NO; /* Length or character mismatch */
! 239: }
! 240:
! 241:
! 242: /* PUBLIC HTAA_makeProtectionTemplate()
! 243: ** CREATE A PROTECTION TEMPLATE FOR THE FILES
! 244: ** IN THE SAME DIRECTORY AS THE GIVEN FILE
! 245: ** (Used by server if there is no fancier way for
! 246: ** it to tell the client, and by browser if server
! 247: ** didn't send WWW-ProtectionTemplate: field)
! 248: ** ON ENTRY:
! 249: ** docname is the document pathname (from URL).
! 250: **
! 251: ** ON EXIT:
! 252: ** returns a template matching docname, and other files
! 253: ** files in that directory.
! 254: **
! 255: ** E.g. /foo/bar/x.html => /foo/bar/ *
! 256: ** ^
! 257: ** Space only to prevent it from
! 258: ** being a comment marker here,
! 259: ** there really isn't any space.
! 260: */
! 261: PUBLIC char *HTAA_makeProtectionTemplate ARGS1(CONST char *, docname)
! 262: {
! 263: char *template = NULL;
! 264: char *slash = NULL;
! 265:
! 266: if (docname) {
! 267: StrAllocCopy(template, docname);
! 268: slash = strrchr(template, '/');
! 269: if (slash) slash++;
! 270: else slash = template;
! 271: *slash = NULL;
! 272: StrAllocCat(template, "*");
! 273: }
! 274: else StrAllocCopy(template, "*");
! 275:
! 276: if (TRACE) fprintf(stderr,
! 277: "make_template: made template `%s' for file `%s'\n",
! 278: template, docname);
! 279:
! 280: return template;
! 281: }
! 282:
! 283:
! 284:
! 285:
! 286: /*
! 287: ** Skip leading whitespace from *s forward
! 288: */
! 289: #define SKIPWS(s) while (*s==' ' || *s=='\t') s++;
! 290:
! 291: /*
! 292: ** Kill trailing whitespace starting from *(s-1) backwords
! 293: */
! 294: #define KILLWS(s) {char *c=s-1; while (*c==' ' || *c=='\t') *(c--)=NULL;}
! 295:
! 296:
! 297: /* PUBLIC HTAA_parseArgList()
! 298: ** PARSE AN ARGUMENT LIST GIVEN IN A HEADER FIELD
! 299: ** ON ENTRY:
! 300: ** str is a comma-separated list:
! 301: **
! 302: ** item, item, item
! 303: ** where
! 304: ** item ::= value
! 305: ** | name=value
! 306: ** | name="value"
! 307: **
! 308: ** Leading and trailing whitespace is ignored
! 309: ** everywhere except inside quotes, so the following
! 310: ** examples are equal:
! 311: **
! 312: ** name=value,foo=bar
! 313: ** name="value",foo="bar"
! 314: ** name = value , foo = bar
! 315: ** name = "value" , foo = "bar"
! 316: **
! 317: ** ON EXIT:
! 318: ** returns a list of name-value pairs (actually HTAssocList*).
! 319: ** For items with no name, just value, the name is
! 320: ** the number of order number of that item. E.g.
! 321: ** "1" for the first, etc.
! 322: */
! 323: PUBLIC HTAssocList *HTAA_parseArgList ARGS1(char *, str)
! 324: {
! 325: HTAssocList *assoc_list = HTAssocList_new();
! 326: char *cur = NULL;
! 327: char *name = NULL;
! 328: int index = 0;
! 329:
! 330: if (!str) return assoc_list;
! 331:
! 332: while (*str) {
! 333: SKIPWS(str); /* Skip leading whitespace */
! 334: cur = str;
! 335: index++;
! 336:
! 337: while (*cur && *cur != '=' && *cur != ',')
! 338: cur++; /* Find end of name (or lonely value without a name) */
! 339: KILLWS(cur); /* Kill trailing whitespace */
! 340:
! 341: if (*cur == '=') { /* Name followed by a value */
! 342: *(cur++) = NULL; /* Terminate name */
! 343: StrAllocCopy(name, str);
! 344: SKIPWS(cur); /* Skip WS leading the value */
! 345: str = cur;
! 346: if (*str == '"') { /* Quoted value */
! 347: str++;
! 348: cur = str;
! 349: while (*cur && *cur != '"') cur++;
! 350: if (*cur == '"')
! 351: *(cur++) = NULL; /* Terminate value */
! 352: /* else it is lacking terminating quote */
! 353: SKIPWS(cur); /* Skip WS leading comma */
! 354: if (*cur == ',') cur++; /* Skip separating colon */
! 355: }
! 356: else { /* Unquoted value */
! 357: while (*cur && *cur != ',') cur++;
! 358: KILLWS(cur); /* Kill trailing whitespace */
! 359: if (*cur == ',')
! 360: *(cur++) = NULL;
! 361: /* else *cur already NULL */
! 362: }
! 363: }
! 364: else { /* No name, just a value */
! 365: if (*cur == ',')
! 366: *(cur++) = NULL; /* Terminate value */
! 367: /* else last value on line (already terminated by NULL) */
! 368: StrAllocCopy(name, "nnn"); /* Room for item order number */
! 369: sprintf(name, "%d", index); /* Item order number for name */
! 370: }
! 371: HTAssocList_add(assoc_list, name, str);
! 372: str = cur;
! 373: } /* while *str */
! 374:
! 375: return assoc_list;
! 376: }
! 377:
! 378:
! 379:
! 380: /************** HEADER LINE READER -- DOES UNFOLDING *************************/
! 381:
! 382: #define BUFFER_SIZE 1024
! 383:
! 384: PRIVATE char buffer[BUFFER_SIZE + 1];
! 385: PRIVATE char *start_pointer = buffer;
! 386: PRIVATE char *end_pointer = buffer;
! 387: PRIVATE int in_soc = -1;
! 388:
! 389: /* PUBLIC HTAA_setupReader()
! 390: ** SET UP HEADER LINE READER, i.e. give
! 391: ** the already-read-but-not-yet-processed
! 392: ** buffer of text to be read before more
! 393: ** is read from the socket.
! 394: ** ON ENTRY:
! 395: ** start_of_headers is a pointer to a buffer containing
! 396: ** the beginning of the header lines
! 397: ** (rest will be read from a socket).
! 398: ** length is the number of valid characters in
! 399: ** 'start_of_headers' buffer.
! 400: ** soc is the socket to use when start_of_headers
! 401: ** buffer is used up.
! 402: ** ON EXIT:
! 403: ** returns nothing.
! 404: ** Subsequent calls to HTAA_getUnfoldedLine()
! 405: ** will use this buffer first and then
! 406: ** proceed to read from socket.
! 407: */
! 408: PUBLIC void HTAA_setupReader ARGS3(char *, start_of_headers,
! 409: int, length,
! 410: int, soc)
! 411: {
! 412: start_pointer = buffer;
! 413: if (start_of_headers) {
! 414: strncpy(buffer, start_of_headers, length);
! 415: buffer[length] = NULL;
! 416: end_pointer = buffer + length;
! 417: }
! 418: else {
! 419: *start_pointer = NULL;
! 420: end_pointer = start_pointer;
! 421: }
! 422: in_soc = soc;
! 423: }
! 424:
! 425:
! 426: /* PUBLIC HTAA_getUnfoldedLine()
! 427: ** READ AN UNFOLDED HEADER LINE FROM SOCKET
! 428: ** ON ENTRY:
! 429: ** HTAA_setupReader must absolutely be called before
! 430: ** this function to set up internal buffer.
! 431: **
! 432: ** ON EXIT:
! 433: ** returns a newly-allocated character string representing
! 434: ** the read line. The line is unfolded, i.e.
! 435: ** lines that begin with whitespace are appended
! 436: ** to current line. E.g.
! 437: **
! 438: ** Field-Name: Blaa-Blaa
! 439: ** This-Is-A-Continuation-Line
! 440: ** Here-Is_Another
! 441: **
! 442: ** is seen by the caller as:
! 443: **
! 444: ** Field-Name: Blaa-Blaa This-Is-A-Continuation-Line Here-Is_Another
! 445: **
! 446: */
! 447: PUBLIC char *HTAA_getUnfoldedLine NOARGS
! 448: {
! 449: char *line = NULL;
! 450: char *cur;
! 451: int count;
! 452: BOOL peek_for_folding = NO;
! 453:
! 454: if (in_soc < 0) {
! 455: fprintf(stderr, "%s %s\n",
! 456: "HTAA_getUnfoldedLine: buffer not initialized",
! 457: "with function HTAA_setupReader()");
! 458: return NULL;
! 459: }
! 460:
! 461: for(;;) {
! 462:
! 463: /* Reading from socket */
! 464:
! 465: if (start_pointer >= end_pointer) {/*Read the next block and continue*/
! 466: count = NETREAD(in_soc, buffer, BUFFER_SIZE);
! 467: if (count <= 0) {
! 468: in_soc = -1;
! 469: return line;
! 470: }
! 471: start_pointer = buffer;
! 472: end_pointer = buffer + count;
! 473: *end_pointer = NULL;
! 474: #ifdef NOT_ASCII
! 475: cur = start_pointer;
! 476: while (cur < end_pointer) {
! 477: *cur = TOASCII(*cur);
! 478: cur++;
! 479: }
! 480: #endif /*NOT_ASCII*/
! 481: }
! 482: cur = start_pointer;
! 483:
! 484:
! 485: /* Unfolding */
! 486:
! 487: if (peek_for_folding) {
! 488: if (*cur != ' ' && *cur != '\t')
! 489: return line; /* Ok, no continuation line */
! 490: else /* So this is a continuation line, continue */
! 491: peek_for_folding = NO;
! 492: }
! 493:
! 494:
! 495: /* Finding end-of-line */
! 496:
! 497: while (cur < end_pointer && *cur != '\n') /* Find the end-of-line */
! 498: cur++; /* (or end-of-buffer). */
! 499:
! 500:
! 501: /* Terminating line */
! 502:
! 503: if (cur < end_pointer) { /* So *cur==LF, terminate line */
! 504: *cur = NULL; /* Overwrite LF */
! 505: if (*(cur-1) == '\r')
! 506: *(cur-1) = NULL; /* Overwrite CR */
! 507: peek_for_folding = YES; /* Check for a continuation line */
! 508: }
! 509:
! 510:
! 511: /* Copying the result */
! 512:
! 513: if (line)
! 514: StrAllocCat(line, start_pointer); /* Append */
! 515: else
! 516: StrAllocCopy(line, start_pointer); /* A new line */
! 517:
! 518: start_pointer = cur+1; /* Skip the read line */
! 519:
! 520: } /* forever */
! 521: }
! 522:
! 523:
! 524:
! 525:
Webmaster