Annotation of libwww/Library/src/HTFilter.c, revision 2.1
2.1 ! frystyk 1: /*
! 2: ** BEFORE AND AFTER FILTERS
! 3: **
! 4: ** (c) COPYRIGHT MIT 1995.
! 5: ** Please first read the full copyright statement in the file COPYRIGH.
! 6: ** @(#) $Id: HTHome.c,v 2.20 1996/07/04 18:40:17 frystyk Exp $
! 7: **
! 8: ** This module implrments a set of default filters that can be registerd
! 9: ** as BEFORE and AFTER filters to the Net manager
! 10: ** Authors
! 11: ** HFN Henrik Frystyk, frystyk@w.org
! 12: ** History
! 13: ** Jul 4, 96 Written
! 14: */
! 15:
! 16: /* Library include files */
! 17: #include "WWWLib.h"
! 18: #include "WWWCache.h"
! 19: #include "WWWRules.h"
! 20: #include "WWWHTTP.h"
! 21: #include "HTLog.h"
! 22: #include "HTAccess.h"
! 23: #include "HTFilter.h" /* Implemented here */
! 24:
! 25: /* ------------------------------------------------------------------------- */
! 26:
! 27: /*
! 28: ** Proxy and Gateway BEFORE filter
! 29: ** -------------------------------
! 30: ** Checks for registerd proxy servers or gateways and sees whether this
! 31: ** request should be redirected to a proxy or a gateway. Proxies have
! 32: ** higher priority than gateways so we look for them first!
! 33: ** For HTTP/1.0 and HTTP/1.1 we may only send a full URL (including the
! 34: ** host portion) to proxy servers. Therefore, we tell the Library whether
! 35: ** to use the full URL or the traditional HTTP one without the host part.
! 36: */
! 37: PUBLIC int HTProxyFilter (HTRequest * request, void * param, int status)
! 38: {
! 39: HTParentAnchor * anchor = HTRequest_anchor(request);
! 40: char * addr = HTAnchor_address((HTAnchor *) anchor);
! 41: char * physical = NULL;
! 42: if ((physical = HTProxy_find(addr))) {
! 43: StrAllocCat(physical, addr);
! 44: HTAnchor_setPhysical(anchor, physical);
! 45: HTRequest_setFullURI(request, YES);
! 46: } else if ((physical = HTGateway_find(addr))) {
! 47: /*
! 48: ** A gateway URL is crated by chopping off any leading "/" to make the
! 49: ** host into part of path
! 50: */
! 51: char * path =
! 52: HTParse(addr, "", PARSE_HOST + PARSE_PATH + PARSE_PUNCTUATION);
! 53: char * gatewayed = HTParse(path+1, physical, PARSE_ALL);
! 54: HTAnchor_setPhysical(anchor, gatewayed);
! 55: HT_FREE(path);
! 56: HT_FREE(gatewayed);
! 57: HTRequest_setFullURI(request, NO);
! 58: } else {
! 59: HTRequest_setFullURI(request, NO);
! 60: }
! 61: HT_FREE(addr);
! 62: return HT_OK;
! 63: }
! 64:
! 65: /*
! 66: ** Rule Translation BEFORE Filter
! 67: ** ------------------------------
! 68: ** If we have a set of rules loaded (see the Rule manager) then check
! 69: ** before each request whether how that should be translated. The trick
! 70: ** is that a parent anchor has a "address" which is the part from the URL
! 71: ** we used when we created the anchor. However, it also have a "physical
! 72: ** address" which is the place we are actually going to look for the
! 73: ** resource. Hence this filter translates from the address to the
! 74: ** physical address (if any translations are found)
! 75: */
! 76: PUBLIC int HTRuleFilter (HTRequest * request, void * param, int status)
! 77: {
! 78: HTList * list = HTRule_global();
! 79: HTParentAnchor * anchor = HTRequest_anchor(request);
! 80: char * addr = HTAnchor_address((HTAnchor *) anchor);
! 81: char * physical = HTRule_translate(list, addr, NO);
! 82: HT_FREE(addr);
! 83: if (!physical) {
! 84: HTRequest_addError(request, ERR_FATAL, NO, HTERR_FORBIDDEN,
! 85: NULL, 0, "HTRuleFilter");
! 86: return HT_ERROR;
! 87: }
! 88: HTAnchor_setPhysical(anchor, physical);
! 89: HT_FREE(physical);
! 90: return HT_OK;
! 91: }
! 92:
! 93: /*
! 94: ** Cache Validation BEFORE Filter
! 95: ** ------------------------------
! 96: ** Check the cache mode to see if we can use an already loaded version
! 97: ** of this document. If so and our copy is valid then we don't have
! 98: ** to go out and get it unless we are forced to
! 99: */
! 100: PUBLIC int HTCacheFilter (HTRequest * request, void * param, int status)
! 101: {
! 102: HTParentAnchor * anchor = HTRequest_anchor(request);
! 103: HTReload mode = HTRequest_reloadMode(request);
! 104: /*
! 105: ** If the mode if "Force Reload" then don't even bother to check the
! 106: ** cache - we flush everything we know about this document
! 107: */
! 108: if (mode == HT_FORCE_RELOAD) {
! 109: /*
! 110: ** Add the appropriate request headers. We use both the "pragma"
! 111: ** and the "cache-control" headers in order to be
! 112: ** backwards compatible with HTP/1.0
! 113: */
! 114: HTRequest_addGnHd(request, HT_G_PRAGMA_NO_CACHE);
! 115:
! 116: /* @@@ CACHE CONTROL @@@ */
! 117:
! 118: /*
! 119: ** We also flush the information in the anchor
! 120: */
! 121: HTAnchor_clearHeader(anchor);
! 122: return HT_OK;
! 123: }
! 124:
! 125: /*
! 126: ** Check the application provided memory cache. This is equivalent to a
! 127: ** history list and does not follow the same cache mechanisms as the
! 128: ** persistent cache
! 129: */
! 130: if (HTMemoryCache_check(request) == HT_LOADED)
! 131: return HT_LOADED;
! 132:
! 133: /*
! 134: ** Check the persistent cache manager. If we have a cache hit then
! 135: ** continue to see if the reload mode requires us to do a validation check.
! 136: ** This filter assumes that we can get the cached version through one of
! 137: ** our protocol modules (for example the file module)
! 138: */
! 139: {
! 140: char * addr = HTAnchor_address((HTAnchor *) anchor);
! 141: char * cache = HTCache_getReference(addr);
! 142: if (cache) {
! 143: if (mode != HT_CACHE_REFRESH) {
! 144: HTAnchor_setPhysical(anchor, cache);
! 145: HTAnchor_setCacheHit(anchor, YES);
! 146: } else {
! 147:
! 148: /* @@@ Do cache validation @@@ */
! 149:
! 150: }
! 151: }
! 152: HT_FREE(addr);
! 153: }
! 154: return HT_OK;
! 155: }
! 156:
! 157: /*
! 158: ** Error and Information AFTER filter
! 159: ** ----------------------------------
! 160: ** It checks the status code from a request and generates an
! 161: ** error/information message if required.
! 162: */
! 163: PUBLIC int HTInfoFilter (HTRequest * request, void * param, int status)
! 164: {
! 165: HTParentAnchor * anchor = HTRequest_anchor(request);
! 166: char * uri = HTAnchor_address((HTAnchor*) anchor);
! 167: switch (status) {
! 168: case HT_RETRY:
! 169: if (PROT_TRACE)
! 170: HTTrace("Load End.... NOT AVAILABLE, RETRY AT %ld\n",
! 171: HTRequest_retryTime(request));
! 172: break;
! 173:
! 174: case HT_ERROR:
! 175: {
! 176: /*
! 177: ** See if we have a function registered for outputting errors.
! 178: ** If so then call it and present the message to the user
! 179: */
! 180: HTAlertCallback *cbf = HTAlert_find(HT_A_MESSAGE);
! 181: if (cbf) (*cbf)(request, HT_A_MESSAGE, HT_MSG_NULL, NULL,
! 182: HTRequest_error(request), NULL);
! 183: if (PROT_TRACE)
! 184: HTTrace("Load End.... ERROR: Can't access `%s\'\n",
! 185: uri ? uri : "<UNKNOWN>");
! 186: break;
! 187: }
! 188:
! 189: default:
! 190: if (PROT_TRACE)
! 191: HTTrace("Load End.... Request ended with code %d\n", status);
! 192: break;
! 193: }
! 194:
! 195: HT_FREE(uri);
! 196: return HT_OK;
! 197: }
! 198:
! 199: /*
! 200: ** Redirection AFTER filter
! 201: ** ------------------------
! 202: ** The redirection handler only handles redirections
! 203: ** on the GET or HEAD method (or any other safe method)
! 204: */
! 205: PUBLIC int HTRedirectFilter (HTRequest * request, void * param, int status)
! 206: {
! 207: HTMethod method = HTRequest_method(request);
! 208: HTAnchor * new_anchor = HTRequest_redirection(request);
! 209:
! 210: /*
! 211: ** Only do redirect on GET and HEAD
! 212: */
! 213: if (!HTMethod_isSafe(method) || !new_anchor) {
! 214: HTRequest_addError(request, ERR_FATAL, NO, HTERR_AUTO_REDIRECT,
! 215: NULL, 0, "RedirectionFilter");
! 216: return HT_ERROR;
! 217: }
! 218:
! 219: /*
! 220: ** Start new request with the redirect anchor found in the headers.
! 221: ** Note that we reuse the same request object which means that we must
! 222: ** keep this around until the redirected request has terminated. It also
! 223: ** allows us in an easy way to keep track of the number of redirections
! 224: ** so that we can detect endless loops.
! 225: */
! 226: if (HTRequest_retry(request)) {
! 227: HTLoadAnchor(new_anchor, request);
! 228: } else {
! 229: HTRequest_addError(request, ERR_FATAL, NO, HTERR_MAX_REDIRECT,
! 230: NULL, 0, "HTRedirectFilter");
! 231: }
! 232:
! 233: /*
! 234: ** By returning HT_ERROR we make sure that this is the last handler to be
! 235: ** called. We do this as we don't want any other filter to delete the
! 236: ** request object now when we have just started a new one ourselves
! 237: */
! 238: return HT_ERROR;
! 239: }
! 240:
! 241: /*
! 242: ** Client side authentication BEFORE filter
! 243: ** ----------------------------------------
! 244: ** The filter generates the credentials required to access a document
! 245: ** Getting the credentials may involve asking the user
! 246: */
! 247: PUBLIC int HTCredentialsFilter (HTRequest * request, void * param, int status)
! 248: {
! 249: /*
! 250: ** Ask the authentication module to call the right credentials generator
! 251: ** that understands this scheme
! 252: */
! 253: if (HTAA_beforeFilter(request, param, status) == HT_OK) {
! 254: if (PROT_TRACE) HTTrace("Credentials. verified\n");
! 255: return HT_OK;
! 256: } else {
! 257: HTRequest_addError(request, ERR_FATAL, NO, HTERR_UNAUTHORIZED,
! 258: NULL, 0, "HTCredentialsFilter");
! 259: return HT_ERROR;
! 260: }
! 261: }
! 262:
! 263: /*
! 264: ** Client side authentication AFTER filter
! 265: ** ---------------------------------------
! 266: ** The client side authentication filter uses the
! 267: ** user dialog messages registered in the HTAlert module.
! 268: ** By default these are the ones used by the line mode browser but you can
! 269: ** just register something else.
! 270: */
! 271: PUBLIC int HTAuthFilter (HTRequest * request, void * param, int status)
! 272: {
! 273: /*
! 274: ** Ask the authentication module to call the right challenge parser
! 275: ** that understands this scheme
! 276: */
! 277: if (HTAA_afterFilter(request, param, status) == HT_OK) {
! 278: HTMethod method = HTRequest_method(request);
! 279:
! 280: if (HTMethod_hasEntity(method)) {
! 281: if (APP_TRACE)
! 282: HTTrace("Auth filter. Can't authenticate PUT or POST\n");
! 283: return HT_ERROR;
! 284: }
! 285:
! 286: /*
! 287: ** Start request with new credentials. As with the redirection filter
! 288: ** we reuse the same request object which means that we must
! 289: ** keep this around until the redirected request has terminated
! 290: */
! 291: HTLoad(request, NO);
! 292:
! 293: /*
! 294: ** We return HT_ERROR to make sure that this is the last handler to be
! 295: ** called. We do this as we don't want any other filter to delete the
! 296: ** request object now when we have just started a new one ourselves
! 297: */
! 298: return HT_ERROR;
! 299: }
! 300: return HT_OK;
! 301: }
! 302:
! 303: /*
! 304: ** Request Loggin AFTER filter
! 305: ** ---------------------------
! 306: ** Default Logging filter using the log manager provided by HTLog.c
! 307: */
! 308: PUBLIC int HTLogFilter (HTRequest * request, void * param, int status)
! 309: {
! 310: if (request) {
! 311: if (HTLog_isOpen()) HTLog_add(request, status);
! 312: return HT_OK;
! 313: }
! 314: return HT_ERROR;
! 315: }
Webmaster