[BACK] Return to HTTP.c CVS log [TXT] [DIR] Up to [Public] / libwww / Library / src

Annotation of libwww/Library/src/HTTP.c, revision 1.80

1.74 frystyk 1: /*                                   HTTP.c
 2: **   MULTITHREADED IMPLEMENTATION OF HTTP CLIENT
1.2 timbl 3: **
1.74 frystyk 4: **   (c) COPYRIGHT CERN 1994.
 5: **   Please first read the full copyright statement in the file COPYRIGH.
 6: **
 7: **   This module implments the HTTP protocol as a state machine
1.55 frystyk 8: **
 9: ** History:
1.59 frystyk 10: **  < May 24 94 ??  Unknown - but obviously written
1.56 frystyk 11: **   May 24 94 HF  Made reentrent and cleaned up a bit. Implemented
 12: **           Forward, redirection, error handling and referer field
1.67 duns 13: **   8 Jul 94 FM  Insulate free() from _free structure element.
1.71 frystyk 14: **   Jul 94 HFN   Written on top of HTTP.c, Henrik Frystyk
1.55 frystyk 15: **
1.1 timbl 16: */
 17: 
1.78 frystyk 18: /* Library include files */
 19: #include "tcp.h"
1.1 timbl 20: #include "HTUtils.h"
1.78 frystyk 21: #include "HTString.h"
1.71 frystyk 22: #include "HTParse.h"
1.1 timbl 23: #include "HTTCP.h"
 24: #include "HTFormat.h"
1.2 timbl 25: #include "HTAlert.h"
 26: #include "HTMIME.h"
1.21 luotonen 27: #include "HTAccess.h"     /* HTRequest */
1.14 luotonen 28: #include "HTAABrow.h"     /* Access Authorization */
1.20 timbl 29: #include "HTTee.h"       /* Tee off a cache stream */
1.78 frystyk 30: #include "HTFWrite.h"     /* Write to cache file */
1.80 ! frystyk 31: #include "HTWriter.h"
1.54 luotonen 32: #include "HTError.h"
1.55 frystyk 33: #include "HTChunk.h"
1.71 frystyk 34: #include "HTGuess.h"
 35: #include "HTThread.h"
1.80 ! frystyk 36: #include "HTTPReq.h"
1.55 frystyk 37: #include "HTTP.h"                       /* Implements */
 38: 
 39: /* Macros and other defines */
1.71 frystyk 40: #define PUTC(c)        (*me->target->isa->put_character)(me->target, c)
 41: #define PUTS(s)        (*me->target->isa->put_string)(me->target, s)
 42: #define PUTBLOCK(b, l) (*me->target->isa->put_block)(me->target, b, l)
 43: #define FREE_TARGET  (*me->target->isa->_free)(me->target)
1.74 frystyk 44: #define ABORT_TARGET  (*me->target->isa->abort)(me->target, e)
1.2 timbl 45: 
1.55 frystyk 46: /* Globals */
1.64 frystyk 47: PUBLIC int HTMaxRedirections = 10;      /* Max number of redirections */
1.23 luotonen 48: 
1.59 frystyk 49: /* Type definitions and global variables etc. local to this module */
 50: /* This is the local definition of HTRequest->net_info */
 51: typedef enum _HTTPState {
1.71 frystyk 52:   HTTP_ERROR     = -3,
 53:   HTTP_NO_DATA    = -2,
 54:   HTTP_GOT_DATA   = -1,
 55:   HTTP_BEGIN     = 0,
 56:   HTTP_NEED_CONNECTION,
 57:   HTTP_NEED_REQUEST,
 58:   HTTP_REDIRECTION,
 59:   HTTP_AA
1.59 frystyk 60: } HTTPState;
1.55 frystyk 61: 
 62: typedef struct _http_info {
1.78 frystyk 63:   SOCKFD       sockfd;             /* Socket descripter */
1.71 frystyk 64:   SockA       sock_addr;       /* SockA is defined in tcp.h */
1.68 frystyk 65:   HTInputSocket *  isoc;                /* Input buffer */
1.80 ! frystyk 66:   SocAction     action;         /* Result of the select call */
 ! 67:   HTStream *     target;               /* Target stream */
1.71 frystyk 68:   int        addressCount;    /* Attempts if multi-homed host */
 69:   time_t       connecttime;       /* Used on multihomed hosts */
 70:   struct _HTRequest *    request;      /* Link back to request structure */
1.68 frystyk 71: 
 72:   HTTPState     state;          /* State of the connection */
1.55 frystyk 73: } http_info;
 74: 
1.80 ! frystyk 75: #define MAX_STATUS_LEN     75  /* Max nb of chars to check StatusLine */
1.55 frystyk 76: 
1.71 frystyk 77: struct _HTStream {
 78:   CONST HTStreamClass *   isa;
 79:   HTStream *         target;
 80:   HTRequest *            request;
 81:   http_info *            http;
 82:   HTSocketEOL            state;
 83:   BOOL            transparent;
1.79 frystyk 84:   double           version;         /* @@@ DOESN'T WORK */
1.71 frystyk 85:   int                status;
 86:   char            buffer[MAX_STATUS_LEN+1];
1.80 ! frystyk 87:   int                buflen;
1.71 frystyk 88: };
1.21 luotonen 89: 
1.71 frystyk 90: /* ------------------------------------------------------------------------- */
 91: /*                Help Functions               */
 92: /* ------------------------------------------------------------------------- */
1.21 luotonen 93: 
1.71 frystyk 94: /*                                 HTTPCleanup
1.1 timbl 95: **
1.55 frystyk 96: **   This function closes the connection and frees memory.
1.1 timbl 97: **
1.55 frystyk 98: **   Returns 0 on OK, else -1
1.1 timbl 99: */
1.80 ! frystyk 100: PRIVATE int HTTPCleanup ARGS2(HTRequest *, req, BOOL, abort)
1.1 timbl 101: {
1.71 frystyk 102:   http_info *http;
1.55 frystyk 103:   int status = 0;
1.80 ! frystyk 104:   if (!req || !req->net_info) {
1.78 frystyk 105:    if (PROT_TRACE) fprintf(TDEST, "HTTPCleanup. Bad argument!\n");
1.55 frystyk 106:    status = -1;
 107:   } else {
1.80 ! frystyk 108:    http = (http_info *) req->net_info;
1.78 frystyk 109:    if (http->sockfd != INVSOC) {
1.80 ! frystyk 110: 
 ! 111:      /* Free stream with data TO network */
 ! 112:      if (!req->PostCallBack) {
 ! 113:        if (abort)
 ! 114:          (*req->input_stream->isa->abort)(req->input_stream, NULL);
 ! 115:        else
 ! 116:          (*req->input_stream->isa->_free)(req->input_stream);
 ! 117:      }
 ! 118:      
 ! 119:      /* Free stream with data FROM network */
 ! 120:      if (abort)
 ! 121:        (*http->target->isa->abort)(http->target, NULL);
 ! 122:      else
 ! 123:        (*http->target->isa->_free)(http->target);
 ! 124: 
1.78 frystyk 125:      if (PROT_TRACE)
 126:        fprintf(TDEST,"HTTP........ Closing socket %d\n",http->sockfd);
1.59 frystyk 127:      if ((status = NETCLOSE(http->sockfd)) < 0)
1.78 frystyk 128:        HTErrorSysAdd(http->request, ERR_FATAL, socerrno, NO,
 129:               "NETCLOSE");
1.71 frystyk 130:      HTThreadState(http->sockfd, THD_CLOSE);
1.80 ! frystyk 131:      http->sockfd = INVSOC;
1.71 frystyk 132:      HTThread_clear((HTNetInfo *) http);
 133:    }
 134:    if (http->isoc)
 135:      HTInputSocket_free(http->isoc);
1.80 ! frystyk 136:    free(http);
 ! 137:    req->net_info = NULL;
1.55 frystyk 138:   } 
 139:   return status;
 140: }
 141: 
 142: 
1.71 frystyk 143: PRIVATE BOOL HTTPAuthentication ARGS1(HTRequest *, request)
 144: {
 145:   HTAAScheme scheme;
 146:   HTList *valid_schemes = HTList_new();
 147:   HTAssocList **scheme_specifics = NULL;
1.76 frystyk 148:   char *tmplate = NULL;
1.71 frystyk 149: 
 150:   if (request->WWWAAScheme) {
 151:    if ((scheme = HTAAScheme_enum(request->WWWAAScheme)) != HTAA_UNKNOWN) {
 152:      HTList_addObject(valid_schemes, (void *) scheme);
 153:      if (!scheme_specifics) {
 154:        int i;
 155:        scheme_specifics = (HTAssocList**)
 156:          malloc(HTAA_MAX_SCHEMES * sizeof(HTAssocList*));
 157:        if (!scheme_specifics)
 158:          outofmem(__FILE__, "HTTPAuthentication");
 159:        for (i=0; i < HTAA_MAX_SCHEMES; i++)
 160:          scheme_specifics[i] = NULL;
 161:      }
 162:      scheme_specifics[scheme] = HTAA_parseArgList(request->WWWAARealm);
 163:    } else if (PROT_TRACE) {
 164:      HTErrorAdd(request, ERR_INFO, NO, HTERR_UNKNOWN_AA,
 165:            (void *) request->WWWAAScheme, 0, "HTTPAuthentication");
 166:      return NO;
 167:    }
 168:   }
 169:   if (request->WWWprotection) {
 170:    if (PROT_TRACE)
1.78 frystyk 171:      fprintf(TDEST, "Protection template set to `%s'\n",
1.71 frystyk 172:          request->WWWprotection);
1.76 frystyk 173:    StrAllocCopy(tmplate, request->WWWprotection);
1.71 frystyk 174:   }
 175:   request->valid_schemes = valid_schemes;
 176:   request->scheme_specifics = scheme_specifics;
1.76 frystyk 177:   request->prot_template = tmplate;
1.71 frystyk 178:   return YES;
 179: }
 180: 
 181: 
 182: /*
 183: **   This is a big switch handling all HTTP return codes. It puts in any
 184: **   appropiate error message and decides whether we should expect data
1.78 frystyk 185: **   or not.
1.55 frystyk 186: */
1.71 frystyk 187: PRIVATE void HTTPResponse ARGS1(HTStream *, me)
1.55 frystyk 188: {
1.71 frystyk 189:   switch (me->status) {
 190: 
1.78 frystyk 191:    case 0:                        /* 0.9 response */
 192:    case 200:
 193:    case 201:
 194:    case 202:
 195:    case 203:
 196:    case 205:
 197:    case 206:
1.71 frystyk 198:    break;
1.78 frystyk 199: 
 200:    case 204:                           /* No Response */
 201:    me->http->state = HTTP_NO_DATA;
1.71 frystyk 202:    break;
1.78 frystyk 203: 
1.71 frystyk 204:    case 301:                              /* Moved */
 205:    case 302:                              /* Found */
 206:    me->http->state = HTTP_REDIRECTION;
 207:    break;
1.55 frystyk 208:    
1.71 frystyk 209:    case 303:                              /* Method */
 210:    HTAlert("This client doesn't support automatic redirection of type `Method'");
 211:    me->http->state = HTTP_ERROR;
 212:    break;
1.55 frystyk 213:    
1.78 frystyk 214:    case 400:                           /* Bad Request */
 215:    HTErrorAdd(me->request, ERR_FATAL, NO, HTERR_BAD_REQUEST,
 216:          NULL, 0, "HTLoadHTTP");
1.71 frystyk 217:    me->http->state = HTTP_ERROR;
 218:    break;
1.70 howcome 219: 
1.71 frystyk 220:    case 401:
1.78 frystyk 221:    HTErrorAdd(me->request, ERR_FATAL, NO, HTERR_UNAUTHORIZED,
 222:          NULL, 0, "HTLoadHTTP");
1.71 frystyk 223:    me->http->state = HTTP_AA;
 224:    break;
 225:    
 226:    case 402:                         /* Payment required */
1.78 frystyk 227:    HTErrorAdd(me->request, ERR_FATAL, NO, HTERR_PAYMENT_REQUIRED,
 228:          NULL, 0, "HTLoadHTTP");
 229:    me->http->state = HTTP_ERROR;
1.71 frystyk 230:    break;
1.55 frystyk 231:    
1.71 frystyk 232:    case 403:                            /* Forbidden */
1.78 frystyk 233:    HTErrorAdd(me->request, ERR_FATAL, NO, HTERR_FORBIDDEN,
 234:          NULL, 0, "HTLoadHTTP");
1.71 frystyk 235:    me->http->state = HTTP_ERROR;
 236:    break;
1.55 frystyk 237:    
1.71 frystyk 238:    case 404:                            /* Not Found */
1.78 frystyk 239:    HTErrorAdd(me->request, ERR_FATAL, NO, HTERR_NOT_FOUND,
 240:          NULL, 0, "HTLoadHTTP");
1.71 frystyk 241:    me->http->state = HTTP_ERROR;
 242:    break;
 243:    
1.78 frystyk 244:    case 405:                           /* Not Allowed */
 245:    HTErrorAdd(me->request, ERR_FATAL, NO, HTERR_NOT_ALLOWED,
 246:          NULL, 0, "HTLoadHTTP");
 247:    me->http->state = HTTP_ERROR;
 248:    break;
 249: 
 250:    case 406:                         /* None Acceptable */
 251:    HTErrorAdd(me->request, ERR_FATAL, NO, HTERR_NONE_ACCEPTABLE,
 252:          NULL, 0, "HTLoadHTTP");
 253:    me->http->state = HTTP_ERROR;
 254:    break;
 255: 
 256:    case 407:                  /* Proxy Authentication Required */
 257:    HTErrorAdd(me->request, ERR_FATAL, NO, HTERR_PROXY,
 258:          NULL, 0, "HTLoadHTTP");
 259:    me->http->state = HTTP_ERROR;
 260:    break;
 261: 
 262:    case 408:                         /* Request Timeout */
 263:    HTErrorAdd(me->request, ERR_FATAL, NO, HTERR_TIMEOUT,
 264:          NULL, 0, "HTLoadHTTP");
 265:    me->http->state = HTTP_ERROR;
 266:    break;
 267: 
1.71 frystyk 268:    case 500:
1.78 frystyk 269:    HTErrorAdd(me->request, ERR_FATAL, NO, HTERR_INTERNAL,
 270:          NULL, 0, "HTLoadHTTP");
 271:    me->http->state = HTTP_ERROR;
 272:    break;
 273:    
1.71 frystyk 274:    case 501:
1.78 frystyk 275:    HTErrorAdd(me->request, ERR_FATAL, NO, HTERR_NOT_IMPLEMENTED,
 276:          NULL, 0, "HTLoadHTTP");
 277:    me->http->state = HTTP_ERROR;
 278:    break;
 279: 
 280:    case 502:
 281:    HTErrorAdd(me->request, ERR_FATAL, NO, HTERR_BAD_GATE,
 282:          NULL, 0, "HTLoadHTTP");
 283:    me->http->state = HTTP_ERROR;
 284:    break;
 285: 
 286:    case 503:
 287:    HTErrorAdd(me->request, ERR_FATAL, NO, HTERR_DOWN,
 288:          NULL, 0, "HTLoadHTTP");
 289:    me->http->state = HTTP_ERROR;
 290:    break;
 291: 
 292:    case 504:
 293:    HTErrorAdd(me->request, ERR_FATAL, NO, HTERR_GATE_TIMEOUT,
 294:          NULL, 0, "HTLoadHTTP");
1.71 frystyk 295:    me->http->state = HTTP_ERROR;
 296:    break;
1.78 frystyk 297: 
1.71 frystyk 298:    default:                        /* bad number */
 299:    HTErrorAdd(me->request, ERR_FATAL, NO, HTERR_BAD_REPLY,
1.80 ! frystyk 300:          (void *) me->buffer, me->buflen, "HTLoadHTTP");
1.71 frystyk 301:    me->http->state = HTTP_ERROR;
 302:    break;
1.55 frystyk 303:   }
 304: }
 305: 
1.71 frystyk 306: /* ------------------------------------------------------------------------- */
 307: /*             HTTP Status Line Stream             */
 308: /* ------------------------------------------------------------------------- */
1.55 frystyk 309: 
1.71 frystyk 310: /*
1.80 ! frystyk 311: **   Analyse the stream we have read. If it is a HTTP 1.0 or higher
1.71 frystyk 312: **   then create a MIME-stream, else create a Guess stream to find out
 313: **   what the 0.9 server is sending. We need to copy the buffer as we don't
 314: **   know if we can modify the contents or not.
1.78 frystyk 315: **
 316: **   Stream handling is a function of the status code returned from the 
 317: **   server:
 318: **       200:   Use `output_stream' in HTRequest structure
1.80 ! frystyk 319: **       else:  Use `error_stream' in HTRequest structure
 ! 320: **
 ! 321: **   Return: YES if buffer should be written out. NO otherwise
1.56 frystyk 322: */
1.80 ! frystyk 323: PRIVATE int stream_pipe ARGS1(HTStream *, me)
1.56 frystyk 324: {
1.71 frystyk 325:   HTRequest *req = me->request;
1.80 ! frystyk 326:   if (me->target) {
 ! 327:    int status = PUTBLOCK(me->buffer, me->buflen);
 ! 328:    if (status == HT_OK)
 ! 329:      me->transparent = YES;
 ! 330:    return status;
 ! 331:   }
 ! 332:   if (strncasecomp(me->buffer, "http/", 5) ||
 ! 333:    sscanf(me->buffer+5, "%lf %d", &me->version, &me->status) < 2) {
 ! 334:    int status;
 ! 335:    HTErrorAdd(req, ERR_INFO, NO, HTERR_HTTP09,
 ! 336:          (void *) me->buffer, me->buflen, "HTTPStatusStream");
 ! 337:    me->target = HTGuess_new(req, NULL, WWW_UNKNOWN,
 ! 338:                 req->output_format, req->output_stream);
 ! 339:    if ((status = PUTBLOCK(me->buffer, me->buflen)) == HT_OK)
 ! 340:      me->transparent = YES;
 ! 341:    return status;
 ! 342:   } else {
 ! 343:    if (req->output_format == WWW_SOURCE) {
 ! 344:      me->target = HTMIMEConvert(req, NULL, WWW_MIME, req->output_format,
 ! 345:                    req->output_stream);
 ! 346:    } else if (me->status==200) {
 ! 347:      HTStream *s;
 ! 348:      me->target = HTStreamStack(WWW_MIME, req->output_format,
 ! 349:                    req->output_stream, req, NO);
 ! 350:      
 ! 351:      /* howcome: test for return value from HTCacheWriter 12/1/95 */
 ! 352:      if (HTCache_isEnabled() &&
 ! 353:        (s = HTCacheWriter(req, NULL, WWW_MIME, req->output_format,
 ! 354:                  req->output_stream))) {
 ! 355:        me->target = HTTee(me->target, s);
 ! 356:      }
1.71 frystyk 357:    } else {
1.80 ! frystyk 358:      me->target = HTStreamStack(WWW_MIME, WWW_SOURCE,
 ! 359:                    req->error_stream ?
 ! 360:                    req->error_stream : HTBlackHole(),
 ! 361:                    req, NO);
1.56 frystyk 362:    }
1.80 ! frystyk 363:    if (!me->target)
 ! 364:      me->target = HTBlackHole();             /* What else */
1.56 frystyk 365:   }
1.80 ! frystyk 366:   me->transparent = YES;
 ! 367:   return HT_OK;
1.71 frystyk 368: }
1.56 frystyk 369: 
1.80 ! frystyk 370: /*
 ! 371: **   Searches for HTTP header line until buffer fills up or a CRLF or LF
 ! 372: **   is found
 ! 373: */
 ! 374: PRIVATE int HTTPStatus_put_block ARGS3(HTStream *, me, CONST char*, b, int, l)
1.71 frystyk 375: {
1.80 ! frystyk 376:   while (!me->transparent && l-- > 0) {
 ! 377:    int status;
 ! 378:    if (me->target) {
 ! 379:      if ((status = stream_pipe(me)) != HT_OK)
 ! 380:        return status;
 ! 381:    } else {
 ! 382:      *(me->buffer+me->buflen++) = *b;
 ! 383:      if (me->state == EOL_FCR) {
 ! 384:        if (*b == LF) { /* Line found */
 ! 385:          if ((status = stream_pipe(me)) != HT_OK)
 ! 386:            return status;
 ! 387:        } else {
 ! 388:          me->state = EOL_BEGIN;
 ! 389:        }
 ! 390:      } else if (*b == CR) {
 ! 391:        me->state = EOL_FCR;
 ! 392:      } else if (*b == LF) {
 ! 393:        if ((status = stream_pipe(me)) != HT_OK)
 ! 394:          return status;
1.71 frystyk 395:      } else {
1.80 ! frystyk 396:        if (me->buflen >= MAX_STATUS_LEN) {
 ! 397:          if ((status = stream_pipe(me)) != HT_OK)
 ! 398:            return status;
 ! 399:        }
1.71 frystyk 400:      }
1.80 ! frystyk 401:      b++;
1.71 frystyk 402:    }
1.56 frystyk 403:   }
1.80 ! frystyk 404:   if (l > 0)
 ! 405:    return PUTBLOCK(b, l);
 ! 406:   return HT_OK;
1.56 frystyk 407: }
 408: 
1.80 ! frystyk 409: PRIVATE int HTTPStatus_put_string ARGS2(HTStream *, me, CONST char*, s)
1.71 frystyk 410: {
1.80 ! frystyk 411:   return HTTPStatus_put_block(me, s, (int) strlen(s));
1.71 frystyk 412: }
1.56 frystyk 413: 
1.80 ! frystyk 414: PRIVATE int HTTPStatus_put_character ARGS2(HTStream *, me, char, c)
1.71 frystyk 415: {
1.80 ! frystyk 416:   return HTTPStatus_put_block(me, &c, 1);
 ! 417: }
 ! 418: 
 ! 419: PRIVATE int HTTPStatus_flush ARGS1(HTStream *, me)
 ! 420: {
 ! 421:   return (*me->target->isa->flush)(me->target);
1.71 frystyk 422: }
 423: 
 424: PRIVATE int HTTPStatus_free ARGS1(HTStream *, me)
 425: {
1.78 frystyk 426:   HTTPResponse(me);                   /* Get next state */
1.71 frystyk 427:   if (me->target)
 428:    FREE_TARGET;
 429:   free(me);
1.80 ! frystyk 430:   return HT_OK;
1.71 frystyk 431: }
 432: 
 433: PRIVATE int HTTPStatus_abort ARGS2(HTStream *, me, HTError, e)
 434: {
 435:   if (me->target)
1.74 frystyk 436:    ABORT_TARGET;
1.71 frystyk 437:   free(me);
1.74 frystyk 438:   if (PROT_TRACE)
1.80 ! frystyk 439:    fprintf(TDEST, "HTTPStatus.. ABORTING...\n");
 ! 440:   return HT_ERROR;
1.71 frystyk 441: }
 442: 
 443: /*   HTTPStatus Stream
 444: **   -----------------
 445: */
 446: PRIVATE CONST HTStreamClass HTTPStatusClass =
 447: {       
 448:   "HTTPStatus",
1.80 ! frystyk 449:   HTTPStatus_flush,
1.71 frystyk 450:   HTTPStatus_free,
 451:   HTTPStatus_abort,
 452:   HTTPStatus_put_character,
 453:   HTTPStatus_put_string,
 454:   HTTPStatus_put_block
 455: };
 456: 
 457: PUBLIC HTStream * HTTPStatus_new ARGS2(HTRequest *, request,
 458:                    http_info *, http)
 459: {
 460:   HTStream * me = (HTStream *) calloc(1, sizeof(HTStream));
 461:   if (!me) outofmem(__FILE__, "HTTPStatus_new");
 462:   me->isa = &HTTPStatusClass;
 463:   me->request = request;
 464:   me->http = http;
 465:   me->state = EOL_BEGIN;
 466:   return me;
 467: }
 468: 
 469: /* ------------------------------------------------------------------------- */
 470: 
 471: /*       Load Document from HTTP Server            HTLoadHTTP
1.55 frystyk 472: **       ==============================
 473: **
 474: **   Given a hypertext address, this routine loads a document.
 475: **
 476: ** On entry,
 477: **   request        This is the request structure
 478: ** On exit,
1.80 ! frystyk 479: **   returns     HT_ERROR    Error has occured or interrupted
1.71 frystyk 480: **           HT_WOULD_BLOCK if operation would have blocked
1.58 frystyk 481: **           HT_LOADED    if return status 200 OK
 482: **           HT_NO_DATA   if return status 204 No Response
1.55 frystyk 483: */
 484: PUBLIC int HTLoadHTTP ARGS1 (HTRequest *, request)
 485: {
1.71 frystyk 486:   int status = HT_ERROR;
 487:   char *url;              /* Gets initialized on every entry */
1.55 frystyk 488:   http_info *http;            /* Specific protocol information */
 489: 
 490:   if (!request || !request->anchor) {
1.78 frystyk 491:     if (PROT_TRACE) fprintf(TDEST, "HTLoadHTTP.. Bad argument\n");
1.71 frystyk 492:     return HT_ERROR;
1.55 frystyk 493:   }
 494:   url = HTAnchor_physical(request->anchor);
1.17 timbl 495:   
1.71 frystyk 496:   /* Only do the setup first time through. This is actually state HTTP_BEGIN
 497:    but it can't be in the state machine as we need the structure first */
 498:   if (!request->net_info) {
1.22 luotonen 499:    /*
1.71 frystyk 500:    ** Initiate a new http structure and bind to request structure
 501:    ** This is actually state HTTP_BEGIN, but it can't be in the state
 502:    ** machine as we need the structure first.
1.22 luotonen 503:    */
1.80 ! frystyk 504:    if (PROT_TRACE) fprintf(TDEST, "HTTP........ Looking for `%s\'\n",url);
1.71 frystyk 505:    if ((http = (http_info *) calloc(1, sizeof(http_info))) == NULL)
 506:      outofmem(__FILE__, "HTLoadHTTP");
1.78 frystyk 507:    http->sockfd = INVSOC;           /* Invalid socket number */
1.71 frystyk 508:    http->request = request;
 509:    http->state = HTTP_BEGIN;
 510:    request->net_info = (HTNetInfo *) http;
 511:    HTThread_new((HTNetInfo *) http);
1.80 ! frystyk 512:    request->input_stream = HTTPRequest_new(request,request->input_stream);
1.71 frystyk 513:   } else
 514:    http = (http_info *) request->net_info;     /* Get existing copy */
 515: 
 516:   /* Now jump into the machine. We know the state from the previous run */
 517:   while (1) {
 518:    switch (http->state) {
 519:     case HTTP_BEGIN:
 520:      /*
 521:       ** Compose authorization information (this was moved here
 522:       ** from after the making of the connection so that the connection
 523:       ** wouldn't have to wait while prompting username and password
 524:       ** from the user).             -- AL 13.10.93
 525:       */
 526:      HTAA_composeAuth(request);
 527:      if (PROT_TRACE) {
 528:        if (request->authorization)
1.78 frystyk 529:          fprintf(TDEST, "HTTP........ Sending Authorization: %s\n",
1.71 frystyk 530:              request->authorization);
 531:        else
1.78 frystyk 532:          fprintf(TDEST,
1.71 frystyk 533:              "HTTP........ Not sending authorization (yet)\n");
 534:      }
 535:      http->state = HTTP_NEED_CONNECTION;
 536:      break;
 537:      
 538:     case HTTP_NEED_CONNECTION:    /* Now let's set up a connection */
 539:      status = HTDoConnect((HTNetInfo *) http, url, TCP_PORT,
 540:                 NULL, NO);
1.80 ! frystyk 541:      if (status == HT_OK) {
1.71 frystyk 542:        if (PROT_TRACE)
1.78 frystyk 543:          fprintf(TDEST, "HTTP........ Connected, socket %d\n",
1.71 frystyk 544:              http->sockfd);
1.80 ! frystyk 545: 
 ! 546:        /* Set up read buffer, streams and concurrent read/write */
1.71 frystyk 547:        http->isoc = HTInputSocket_new(http->sockfd);
1.80 ! frystyk 548:        request->input_stream->target=HTWriter_new(http->sockfd, YES);
 ! 549:        http->target = HTImProxy ?
 ! 550:          request->output_stream : HTTPStatus_new(request, http);
 ! 551:        HTThreadState(http->isoc->input_file_number, THD_SET_READ);
1.71 frystyk 552:        http->state = HTTP_NEED_REQUEST;
 553:      } else if (status == HT_WOULD_BLOCK)
 554:        return status;
 555:      else
 556:        http->state = HTTP_ERROR;       /* Error or interrupt */
 557:      break;
 558: 
1.80 ! frystyk 559:      /* As we can do simultanous read and write this is now 1 state */
 ! 560:     case HTTP_NEED_REQUEST:
 ! 561:      if (http->action == SOC_WRITE) {
 ! 562: 
 ! 563:        /* Find the right way to call back */
 ! 564:        if (request->CopyRequest) {
 ! 565:          if (!HTAnchor_headerParsed(request->CopyRequest->anchor))
 ! 566:            return HT_WOULD_BLOCK;
 ! 567:          status = request->PostCallBack(request->CopyRequest,
 ! 568:                          request->input_stream);
 ! 569:        } else if (request->PostCallBack) {
 ! 570:          status = request->PostCallBack(request,
 ! 571:                          request->input_stream);
 ! 572:        } else {
 ! 573:          status = (*request->input_stream->isa->flush)
 ! 574:            (request->input_stream);
 ! 575:        }
1.71 frystyk 576:        if (status == HT_WOULD_BLOCK)
1.80 ! frystyk 577:          return HT_WOULD_BLOCK;
 ! 578:        else if (status == HT_INTERRUPTED)
 ! 579:          http->state = HTTP_ERROR;
1.71 frystyk 580:        else
1.80 ! frystyk 581:          http->action = SOC_READ;
 ! 582:      } else if (http->action == SOC_READ) {
 ! 583:        status = HTSocketRead(request, http->target);
 ! 584:        if (status == HT_WOULD_BLOCK)
 ! 585:          return HT_WOULD_BLOCK;
 ! 586:        else if (status == HT_INTERRUPTED)
1.71 frystyk 587:          http->state = HTTP_ERROR;
1.80 ! frystyk 588:        else if (status == HT_LOADED) {
 ! 589:          if (http->state == HTTP_NEED_REQUEST)
 ! 590:            http->state = HTTP_GOT_DATA;
 ! 591:        } else
 ! 592:          http->state = HTTP_ERROR;
 ! 593:      } else
1.78 frystyk 594:        http->state = HTTP_ERROR;
1.71 frystyk 595:      break;
1.80 ! frystyk 596:      
 ! 597:     case HTTP_REDIRECTION:
1.71 frystyk 598:      if (request->redirect) {
 599:        HTAnchor *anchor;
 600:        if (status == 301) {
 601:          HTErrorAdd(request, ERR_INFO, NO, HTERR_MOVED,
 602:                (void *) request->redirect,
 603:                (int) strlen(request->redirect), "HTLoadHTTP");
 604:        } else if (status == 302) {
 605:          HTErrorAdd(request, ERR_INFO, NO, HTERR_FOUND,
 606:                (void *) request->redirect,
 607:                (int) strlen(request->redirect), "HTLoadHTTP");
1.55 frystyk 608:        }
1.71 frystyk 609:        anchor = HTAnchor_findAddress(request->redirect);
 610:        if (++request->redirections < HTMaxRedirections) {
1.80 ! frystyk 611:          HTTPCleanup(request, NO);
1.71 frystyk 612:          return HTLoadAnchorRecursive((HTAnchor *) anchor, request);
 613:        } else {
 614:          HTErrorAdd(request, ERR_FATAL, NO, HTERR_MAX_REDIRECT,
1.58 frystyk 615:                NULL, 0, "HTLoadHTTP");
1.71 frystyk 616:          http->state = HTTP_ERROR;
1.58 frystyk 617:        }
1.71 frystyk 618:      } else {
 619:        HTErrorAdd(request, ERR_FATAL, NO, HTERR_BAD_REPLY,
 620:              NULL, 0, "HTLoadHTTP");
 621:        http->state = HTTP_ERROR;
 622:      }
 623:      break;
1.80 ! frystyk 624:      
1.71 frystyk 625:     case HTTP_AA:
1.80 ! frystyk 626:      HTTPCleanup(request, NO);          /* Close connection */
1.71 frystyk 627:      if (HTTPAuthentication(request) == YES &&
 628:        HTAA_retryWithAuth(request) == YES) {
 629:        return HTLoadAnchor((HTAnchor *) request->anchor, request);
 630:      } else {
 631:        char *unescaped = NULL;
 632:        StrAllocCopy(unescaped, url);
 633:        HTUnEscape(unescaped);
 634:        HTErrorAdd(request, ERR_FATAL, NO, HTERR_UNAUTHORIZED,
 635:              (void *) unescaped,
 636:              (int) strlen(unescaped), "HTLoadHTTP");
 637:        free(unescaped);
1.80 ! frystyk 638:        return HT_ERROR;
1.71 frystyk 639:      }
 640:      break;
1.80 ! frystyk 641:      
1.71 frystyk 642:     case HTTP_GOT_DATA:
1.80 ! frystyk 643:      HTTPCleanup(request, NO);
1.71 frystyk 644:      return HT_LOADED;
 645:      break;
 646:      
 647:     case HTTP_NO_DATA:
1.80 ! frystyk 648:      HTTPCleanup(request, NO);
1.71 frystyk 649:      return HT_NO_DATA;
 650:      break;
1.80 ! frystyk 651:      
1.71 frystyk 652:     case HTTP_ERROR:
1.80 ! frystyk 653:      HTTPCleanup(request, YES);
1.71 frystyk 654:      return HT_ERROR;
 655:      break;
 656:    }
 657:   } /* End of while(1) */
 658: }  
 659: 
 660: /* Protocol descriptor */
 661: 
 662: GLOBALDEF PUBLIC HTProtocol HTTP = {
 663:   "http", SOC_NON_BLOCK, HTLoadHTTP, NULL, NULL
 664: };
1.21 luotonen 665: 

Webmaster

AltStyle によって変換されたページ (->オリジナル) /