Annotation of libwww/Library/src/HTProxy.c, revision 2.17
2.1 frystyk 1: /* HTProxy.c
2: ** GATEWAY AND PROXY MANAGER
3: **
4: ** (c) COPYRIGHT MIT 1995.
5: ** Please first read the full copyright statement in the file COPYRIGH.
2.17 ! frystyk 6: ** @(#) $Id: HTProxy.c,v 2.16 1998/07/09 17:08:12 frystyk Exp $
2.1 frystyk 7: **
8: ** Replaces the old env variables for gateways and proxies. However for
9: ** backward compatibility there is a function that reads the env variables
10: ** at start up. Note that there is a difference between a proxy and a
11: ** gateway!
12: **
13: ** Authors
14: ** HF Henrik Frystyk, frystyk@w3.org
15: ** History
16: ** 4 Jun 95 Written on a rainy day
17: */
18:
19: #if !defined(HT_DIRECT_WAIS) && !defined(HT_DEFAULT_WAIS_GATEWAY)
20: #define HT_DEFAULT_WAIS_GATEWAY "http://www.w3.org:8001/"
21: #endif
22:
23: /* Library include files */
2.15 frystyk 24: #include "wwwsys.h"
2.11 frystyk 25: #include "WWWUtil.h"
26: #include "WWWCore.h"
27: #include "WWWHTTP.h"
2.12 frystyk 28: #include "WWWApp.h"
2.1 frystyk 29: #include "HTProxy.h" /* Implemented here */
30:
31: /* Variables and typedefs local to this module */
32:
33: typedef struct _HTProxy {
34: char * access;
35: char * url; /* URL of Gateway or Proxy */
2.17 ! frystyk 36: #ifdef HT_POSIX_REGEX
! 37: regex_t * regex; /* Compiled regex */
! 38: #endif
2.1 frystyk 39: } HTProxy;
40:
41: typedef struct _HTHostlist {
42: char * access;
2.17 ! frystyk 43: char * host; /* Host or domain name */
2.1 frystyk 44: unsigned port;
2.17 ! frystyk 45: #ifdef HT_POSIX_REGEX
! 46: regex_t * regex; /* Compiled regex */
! 47: #endif
2.1 frystyk 48: } HTHostList;
49:
50: PRIVATE HTList * proxies = NULL; /* List of proxy servers */
51: PRIVATE HTList * gateways = NULL; /* List of gateways */
52: PRIVATE HTList * noproxy = NULL; /* Don't proxy on these hosts and domains */
53:
54: #if 0
55: PRIVATE HTList * onlyproxy = NULL; /* Proxy only on these hosts and domains */
56: #endif
57:
58: /* ------------------------------------------------------------------------- */
59:
2.17 ! frystyk 60: #ifdef HT_POSIX_REGEX
! 61: PRIVATE char * get_regex_error (int errcode, regex_t * compiled)
! 62: {
! 63: size_t length = regerror (errcode, compiled, NULL, 0);
! 64: char * str = NULL;
! 65: if ((str = (char *) HT_MALLOC(length+1)) == NULL)
! 66: HT_OUTOFMEM("get_regex_error");
! 67: (void) regerror (errcode, compiled, str, length);
! 68: return str;
! 69: }
! 70:
! 71: PRIVATE regex_t * get_regex_t (const char * regex_str, int cflags)
! 72: {
! 73: regex_t * regex = NULL;
! 74: if (regex_str && *regex_str) {
! 75: int status;
! 76: if ((regex = (regex_t *) HT_CALLOC(1, sizeof(regex_t))) == NULL)
! 77: HT_OUTOFMEM("get_regex_t");
! 78: if ((status = regcomp(regex, regex_str, cflags))) {
! 79: char * err_msg = get_regex_error(status, regex);
! 80: if (PROT_TRACE)
! 81: HTTrace("HTProxy..... Regular expression error: %s\n", err_msg);
! 82: HT_FREE(err_msg);
! 83: HT_FREE(regex);
! 84: }
! 85: }
! 86: return regex;
! 87: }
! 88: #endif
! 89:
2.4 frystyk 90: /*
2.1 frystyk 91: ** Existing entries are replaced with new ones
92: */
2.17 ! frystyk 93: PRIVATE BOOL add_object (HTList * list, const char * access, const char * url,
! 94: BOOL regex, int regex_flags)
2.1 frystyk 95: {
96: HTProxy *me;
97: if (!list || !access || !url || !*url)
98: return NO;
2.7 frystyk 99: if ((me = (HTProxy *) HT_CALLOC(1, sizeof(HTProxy))) == NULL)
100: HT_OUTOFMEM("add_object");
2.1 frystyk 101: StrAllocCopy(me->access, access); /* Access method */
2.17 ! frystyk 102:
! 103: #ifdef HT_POSIX_REGEX
! 104: /*
! 105: ** If we support regular expressions then compile one up for
! 106: ** this regular expression. Otherwise use is as a normal
! 107: ** access scheme.
! 108: */
! 109: if (regex) {
! 110: me->regex = get_regex_t(access,
! 111: regex_flags < 0 ?
! 112: W3C_DEFAULT_REGEX_FLAGS : regex_flags);
! 113: } else
! 114: #endif
2.1 frystyk 115: {
116: char *ptr = me->access;
117: while ((*ptr = TOLOWER(*ptr))) ptr++;
118: }
2.17 ! frystyk 119:
2.1 frystyk 120: me->url = HTParse(url, "", PARSE_ACCESS+PARSE_HOST+PARSE_PUNCTUATION);
121: if (*(me->url+strlen(me->url)-1) != '/')
122: StrAllocCat(me->url, "/");
123: me->url = HTSimplify(&me->url);
124:
125: /* See if we already have this one */
126: {
127: HTList *cur = list;
128: HTProxy *pres;
129: while ((pres = (HTProxy *) HTList_nextObject(cur)) != NULL) {
130: if (!strcmp(pres->access, me->access))
131: break; /* We already have it */
132: }
133: if (pres) {
2.3 frystyk 134: if (PROT_TRACE)
2.8 eric 135: HTTrace("HTProxy..... replacing for `%s\' access %s\n",
2.1 frystyk 136: me->url, me->access);
2.7 frystyk 137: HT_FREE(pres->access);
138: HT_FREE(pres->url);
2.17 ! frystyk 139: #ifdef HT_POSIX_REGEX
! 140: if (pres->regex) regfree(pres->regex);
! 141: #endif
2.1 frystyk 142: HTList_removeObject(list, (void *) pres);
2.7 frystyk 143: HT_FREE(pres);
2.1 frystyk 144: }
2.3 frystyk 145: if (PROT_TRACE)
2.8 eric 146: HTTrace("HTProxy..... adding for `%s\' access %s\n",
2.1 frystyk 147: me->url, me->access);
148: HTList_addObject(list, (void *) me);
149: }
150: return YES;
151: }
152:
2.4 frystyk 153: PRIVATE BOOL remove_allObjects (HTList * list)
2.1 frystyk 154: {
155: if (list) {
156: HTList *cur = list;
157: HTProxy *pres;
158: while ((pres = (HTProxy *) HTList_nextObject(cur)) != NULL) {
2.7 frystyk 159: HT_FREE(pres->access);
160: HT_FREE(pres->url);
2.17 ! frystyk 161: #ifdef HT_POSIX_REGEX
! 162: if (pres->regex) regfree(pres->regex);
! 163: #endif
2.7 frystyk 164: HT_FREE(pres);
2.1 frystyk 165: }
166: return YES;
167: }
168: return NO;
169: }
170:
2.4 frystyk 171: /* Add an entry to a list of host names
172: ** ------------------------------------
173: ** Existing entries are replaced with new ones
174: */
2.9 frystyk 175: PRIVATE BOOL add_hostname (HTList * list, const char * host,
2.17 ! frystyk 176: const char * access, unsigned port,
! 177: BOOL regex, int regex_flags)
2.4 frystyk 178: {
179: HTHostList *me;
180: if (!list || !host || !*host)
181: return NO;
2.7 frystyk 182: if ((me = (HTHostList *) HT_CALLOC(1, sizeof(HTHostList))) == NULL)
183: HT_OUTOFMEM("add_hostname");
2.17 ! frystyk 184: #ifdef HT_POSIX_REGEX
! 185: if (regex)
! 186: me->regex = get_regex_t(host,
! 187: regex_flags < 0 ?
! 188: W3C_DEFAULT_REGEX_FLAGS : regex_flags);
! 189: #endif
! 190:
2.4 frystyk 191: if (access) {
192: char *ptr;
193: StrAllocCopy(me->access, access); /* Access method */
194: ptr = me->access;
195: while ((*ptr = TOLOWER(*ptr))) ptr++;
196: }
197: StrAllocCopy(me->host, host); /* Host name */
198: {
199: char *ptr = me->host;
200: while ((*ptr = TOLOWER(*ptr))) ptr++;
201: }
202: me->port = port; /* Port number */
203: if (PROT_TRACE)
2.8 eric 204: HTTrace("HTHostList.. adding `%s\' to list\n", me->host);
2.4 frystyk 205: HTList_addObject(list, (void *) me);
206: return YES;
207: }
2.1 frystyk 208:
2.4 frystyk 209: PRIVATE BOOL remove_AllHostnames (HTList * list)
210: {
211: if (list) {
212: HTList *cur = list;
213: HTHostList *pres;
214: while ((pres = (HTHostList *) HTList_nextObject(cur)) != NULL) {
2.7 frystyk 215: HT_FREE(pres->access);
216: HT_FREE(pres->host);
2.17 ! frystyk 217: #ifdef HT_POSIX_REGEX
! 218: if (pres->regex) regfree(pres->regex);
! 219: #endif
2.7 frystyk 220: HT_FREE(pres);
2.4 frystyk 221: }
222: return YES;
223: }
224: return NO;
225: }
226:
227: /* HTProxy_add
228: ** -----------
2.1 frystyk 229: ** Registers a proxy as the server to contact for a specific
230: ** access method. `proxy' should be a fully valid name, like
231: ** "http://proxy.w3.org:8001" but domain name is not required.
232: ** If an entry exists for this access then delete it and use the
233: ** ne one. Returns YES if OK, else NO
234: */
2.9 frystyk 235: PUBLIC BOOL HTProxy_add (const char * access, const char * proxy)
2.1 frystyk 236: {
2.11 frystyk 237: /*
238: ** If this is the first time here then also add a before filter to handle
2.12 frystyk 239: ** proxy authentication and the normal AA after filter as well.
240: ** These filters will be removed if we remove all proxies again.
2.11 frystyk 241: */
242: if (!proxies) {
243: proxies = HTList_new();
2.13 frystyk 244: HTNet_addBefore(HTAA_proxyBeforeFilter, NULL, NULL,
245: HT_FILTER_MIDDLE);
246: HTNet_addAfter(HTAuthFilter, NULL, NULL,
247: HT_NO_PROXY_ACCESS, HT_FILTER_MIDDLE);
2.14 frystyk 248: HTNet_addAfter(HTAuthFilter, NULL, NULL,
249: HT_PROXY_REAUTH, HT_FILTER_MIDDLE);
2.11 frystyk 250: }
2.17 ! frystyk 251: return add_object(proxies, access, proxy, NO, -1);
! 252: }
! 253:
! 254: /* HTProxy_addRegex
! 255: ** ----------------
! 256: ** Registers a proxy as the server to contact for any URL matching the
! 257: ** regular expression. `proxy' should be a fully valid name, like
! 258: ** "http://proxy.w3.org:8001".
! 259: ** If an entry exists for this access then delete it and use the
! 260: ** new one. Returns YES if OK, else NO
! 261: */
! 262: PUBLIC BOOL HTProxy_addRegex (const char * regex,
! 263: const char * proxy,
! 264: int regex_flags)
! 265: {
! 266: /*
! 267: ** If this is the first time here then also add a before filter to handle
! 268: ** proxy authentication and the normal AA after filter as well.
! 269: ** These filters will be removed if we remove all proxies again.
! 270: */
! 271: if (!proxies) {
! 272: proxies = HTList_new();
! 273: HTNet_addBefore(HTAA_proxyBeforeFilter, NULL, NULL,
! 274: HT_FILTER_MIDDLE);
! 275: HTNet_addAfter(HTAuthFilter, NULL, NULL,
! 276: HT_NO_PROXY_ACCESS, HT_FILTER_MIDDLE);
! 277: HTNet_addAfter(HTAuthFilter, NULL, NULL,
! 278: HT_PROXY_REAUTH, HT_FILTER_MIDDLE);
! 279: }
! 280: #ifdef HT_POSIX_REGEX
! 281: return add_object(proxies, regex, proxy, YES, regex_flags);
! 282: #else
! 283: return add_object(proxies, regex, proxy, NO, -1);
! 284: #endif
2.1 frystyk 285: }
286:
2.4 frystyk 287: /*
2.1 frystyk 288: ** Removes all registered proxies
289: */
2.4 frystyk 290: PUBLIC BOOL HTProxy_deleteAll (void)
2.1 frystyk 291: {
2.4 frystyk 292: if (remove_allObjects(proxies)) {
2.1 frystyk 293: HTList_delete(proxies);
2.11 frystyk 294:
295: /*
296: ** If we have no more proxies then there is no reason for checking
2.12 frystyk 297: ** proxy authentication. We therefore unregister the filters for
298: ** handling proxy authentication
2.11 frystyk 299: */
2.13 frystyk 300: HTNet_deleteBefore(HTAA_proxyBeforeFilter);
2.16 frystyk 301: HTNet_deleteAfter(HTAuthFilter);
2.11 frystyk 302:
2.1 frystyk 303: proxies = NULL;
304: return YES;
305: }
306: return NO;
307: }
308:
2.4 frystyk 309: /* HTGateway_add
310: ** -------------
2.1 frystyk 311: ** Registers a gateway as the server to contact for a specific
312: ** access method. `gateway' should be a fully valid name, like
313: ** "http://gateway.w3.org:8001" but domain name is not required.
314: ** If an entry exists for this access then delete it and use the
315: ** ne one. Returns YES if OK, else NO
316: */
2.9 frystyk 317: PUBLIC BOOL HTGateway_add (const char * access, const char * gate)
2.1 frystyk 318: {
319: if (!gateways)
320: gateways = HTList_new();
2.17 ! frystyk 321: return add_object(gateways, access, gate, NO, -1);
2.1 frystyk 322: }
323:
2.4 frystyk 324: /*
2.1 frystyk 325: ** Removes all registered gateways
326: */
2.4 frystyk 327: PUBLIC BOOL HTGateway_deleteAll (void)
2.1 frystyk 328: {
2.4 frystyk 329: if (remove_allObjects(gateways)) {
2.1 frystyk 330: HTList_delete(gateways);
331: gateways = NULL;
332: return YES;
333: }
334: return NO;
335: }
336:
2.4 frystyk 337: /* HTNoProxy_add
338: ** -------------
2.1 frystyk 339: ** Registers a host name or a domain as a place where no proxy should
340: ** be contacted - for example a very fast link. If `port' is '0' then
341: ** it applies to all ports and if `access' is NULL then it applies to
342: ** to all access methods.
343: **
344: ** Examples: w3.org
345: ** www.close.com
346: */
2.9 frystyk 347: PUBLIC BOOL HTNoProxy_add (const char * host, const char * access,
2.4 frystyk 348: unsigned port)
2.1 frystyk 349: {
350: if (!noproxy)
351: noproxy = HTList_new();
2.17 ! frystyk 352: return add_hostname(noproxy, host, access, port, NO, -1);
! 353: }
! 354:
! 355: /* HTNoProxy_addRegex
! 356: ** ------------------
! 357: ** Registers a regular expression where URIs matching this expression
! 358: ** should go directly and not via a proxy.
! 359: **
! 360: */
! 361: PUBLIC BOOL HTNoProxy_addRegex (const char * regex, int regex_flags)
! 362: {
! 363: if (!noproxy)
! 364: noproxy = HTList_new();
! 365: #ifdef HT_POSIX_REGEX
! 366: return add_hostname(noproxy, regex, NULL, 0, YES, regex_flags);
! 367: #else
! 368: return add_hostname(noproxy, regex, NULL, 0, NO, -1);
! 369: #endif
2.1 frystyk 370: }
371:
2.4 frystyk 372: /* HTNoProxy_deleteAll
373: ** -------------------
2.1 frystyk 374: ** Removes all registered no_proxy directives
375: */
2.4 frystyk 376: PUBLIC BOOL HTNoProxy_deleteAll (void)
2.1 frystyk 377: {
2.4 frystyk 378: if (remove_AllHostnames(noproxy)) {
2.1 frystyk 379: HTList_delete(noproxy);
380: noproxy = NULL;
381: return YES;
382: }
383: return NO;
384: }
385:
2.4 frystyk 386: /* HTProxy_find
387: ** ------------
2.1 frystyk 388: ** This function evaluates the lists of registered proxies and if
389: ** one is found for the actual access method and it is not registered
390: ** in the `noproxy' list, then a URL containing the host to be contacted
391: ** is returned to the caller. This string must be freed be the caller.
392: **
393: ** Returns: proxy If OK (must be freed by caller)
394: ** NULL If no proxy is found or error
395: */
2.9 frystyk 396: PUBLIC char * HTProxy_find (const char * url)
2.1 frystyk 397: {
398: char * access;
399: char * proxy = NULL;
400: if (!url || !proxies)
401: return NULL;
402: access = HTParse(url, "", PARSE_ACCESS);
403:
404: /* First check if the host (if any) is registered in the noproxy list */
405: if (noproxy) {
406: char *host = HTParse(url, "", PARSE_HOST);
407: char *ptr;
408: unsigned port=0;
409: if ((ptr = strchr(host, ':')) != NULL) {
410: *ptr++ = '\0'; /* Chop off port */
411: if (*ptr) port = (unsigned) atoi(ptr);
412: }
413: if (*host) { /* If we have a host name */
414: HTList *cur = noproxy;
415: HTHostList *pres;
416: while ((pres = (HTHostList *) HTList_nextObject(cur)) != NULL) {
2.17 ! frystyk 417: #ifdef HT_POSIX_REGEX
! 418: if (pres->regex) {
! 419: BOOL match = regexec(pres->regex, url, 0, NULL, 0) ? NO : YES;
! 420: if (match) {
! 421: if (PROT_TRACE)
! 422: HTTrace("GetProxy.... No proxy directive found: `%s\'\n", pres->host);
! 423: HT_FREE(access);
! 424: return NULL;
! 425: }
! 426: } else
! 427: #endif
2.1 frystyk 428: if (!pres->access ||
429: (pres->access && !strcmp(pres->access, access))) {
430: if (pres->port == port) {
431: char *np = pres->host+strlen(pres->host);
432: char *hp = host+strlen(host);
433: while (np>=pres->host && hp>=host && (*np--==*hp--));
434: if (np==pres->host-1 && (hp==host-1 || *hp=='.')) {
2.3 frystyk 435: if (PROT_TRACE)
2.8 eric 436: HTTrace("GetProxy.... No proxy directive found: `%s\'\n", pres->host);
2.7 frystyk 437: HT_FREE(access);
2.1 frystyk 438: return NULL;
439: }
440: }
441: }
442: }
443: }
2.7 frystyk 444: HT_FREE(host);
2.1 frystyk 445: }
446:
447: /* Now check if we have a proxy registered for this access method */
448: {
449: HTList *cur = proxies;
450: HTProxy *pres;
451: while ((pres = (HTProxy *) HTList_nextObject(cur)) != NULL) {
2.17 ! frystyk 452: #ifdef HT_POSIX_REGEX
! 453: if (pres->regex) {
! 454: BOOL match = regexec(pres->regex, url, 0, NULL, 0) ? NO : YES;
! 455: if (match) {
! 456: StrAllocCopy(proxy, pres->url);
! 457: if (PROT_TRACE)
! 458: HTTrace("GetProxy.... Found: `%s\'\n", pres->url);
! 459: break;
! 460: }
! 461: } else
! 462: #endif
2.1 frystyk 463: if (!strcmp(pres->access, access)) {
464: StrAllocCopy(proxy, pres->url);
2.2 frystyk 465: if (PROT_TRACE)
2.8 eric 466: HTTrace("GetProxy.... Found: `%s\'\n", pres->url);
2.1 frystyk 467: break;
468: }
469: }
470: }
2.7 frystyk 471: HT_FREE(access);
2.1 frystyk 472: return proxy;
2.9 frystyk 473: }
2.1 frystyk 474:
475:
2.4 frystyk 476: /* HTGateway_find
477: ** --------------
2.1 frystyk 478: ** This function evaluates the lists of registered gateways and if
479: ** one is found for the actual access method then it is returned
480: **
481: ** Returns: gateway If OK (must be freed by caller)
482: ** NULL If no gateway is found or error
483: */
2.9 frystyk 484: PUBLIC char * HTGateway_find (const char * url)
2.1 frystyk 485: {
486: char * access;
487: char * gateway = NULL;
488: if (!url || !gateways)
489: return NULL;
490: access = HTParse(url, "", PARSE_ACCESS);
491:
492: /* Check if we have a gateway registered for this access method */
493: {
494: HTList *cur = gateways;
495: HTProxy *pres;
496: while ((pres = (HTProxy *) HTList_nextObject(cur)) != NULL) {
497: if (!strcmp(pres->access, access)) {
498: StrAllocCopy(gateway, pres->url);
2.2 frystyk 499: if (PROT_TRACE)
2.8 eric 500: HTTrace("GetGateway.. Found: `%s\'\n", pres->url);
2.1 frystyk 501: break;
502: }
503: }
504: }
2.7 frystyk 505: HT_FREE(access);
2.1 frystyk 506: return gateway;
507: }
508:
509:
510: /*
511: ** This function maintains backwards compatibility with the old
512: ** environment variables and searches for the most common values:
513: ** http, ftp, news, wais, and gopher
514: */
2.4 frystyk 515: PUBLIC void HTProxy_getEnvVar (void)
2.1 frystyk 516: {
517: char buf[80];
2.9 frystyk 518: static const char *accesslist[] = {
2.1 frystyk 519: "http",
520: "ftp",
521: "news",
522: "wais",
523: "gopher",
524: NULL
525: };
2.9 frystyk 526: const char **access = accesslist;
2.11 frystyk 527: if (PROT_TRACE)HTTrace("Proxy....... Looking for environment variables\n");
2.1 frystyk 528: while (*access) {
2.11 frystyk 529: BOOL found = NO;
2.1 frystyk 530: char *gateway=NULL;
531: char *proxy=NULL;
532:
2.11 frystyk 533: /* Search for proxy gateways */
534: if (found == NO) {
535: strcpy(buf, *access);
536: strcat(buf, "_proxy");
537: if ((proxy = (char *) getenv(buf)) && *proxy) {
538: HTProxy_add(*access, proxy);
539: found = YES;
540: }
541:
542: /* Try the same with upper case */
543: if (found == NO) {
544: char * up = buf;
545: while ((*up = TOUPPER(*up))) up++;
546: if ((proxy = (char *) getenv(buf)) && *proxy) {
547: HTProxy_add(*access, proxy);
548: found = YES;
549: }
550: }
551: }
552:
553: /* As a last resort, search for gateway servers */
554: if (found == NO) {
555: strcpy(buf, "WWW_");
556: strcat(buf, *access);
557: strcat(buf, "_GATEWAY");
558: if ((gateway = (char *) getenv(buf)) && *gateway) {
559: HTGateway_add(*access, gateway);
560: found = YES;
561: }
562: }
2.1 frystyk 563: ++access;
564: }
565:
566: /* Search for `noproxy' directive */
567: {
568: char *noproxy = getenv("no_proxy");
569: if (noproxy && *noproxy) {
570: char *str = NULL;
571: char *strptr;
572: char *name;
573: StrAllocCopy(str, noproxy); /* Get copy we can mutilate */
574: strptr = str;
575: while ((name = HTNextField(&strptr)) != NULL) {
576: char *portstr = strchr(name, ':');
577: unsigned port=0;
578: if (portstr) {
579: *portstr++ = '\0';
580: if (*portstr) port = (unsigned) atoi(portstr);
581: }
582:
583: /* Register it for all access methods */
2.4 frystyk 584: HTNoProxy_add(name, NULL, port);
2.1 frystyk 585: }
2.7 frystyk 586: HT_FREE(str);
2.1 frystyk 587: }
588: }
589: }
590:
Webmaster