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

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

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.54 luotonen 31: #include "HTError.h"
1.55 frystyk 32: #include "HTChunk.h"
1.71 frystyk 33: #include "HTGuess.h"
 34: #include "HTThread.h"
1.79.2.1! cbrooks 35: #include "HTEvent.h"
1.55 frystyk 36: #include "HTTP.h"                       /* Implements */
 37: 
 38: /* Macros and other defines */
1.71 frystyk 39: #define HTTP_VERSION  "HTTP/1.0"
 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.59 frystyk 47: extern char * HTAppName;         /* Application name: please supply */
 48: extern char * HTAppVersion;      /* Application version: please supply */
1.72 frystyk 49: extern BOOL using_proxy;          /* are we using a proxy gateway? */
1.71 frystyk 50: 
1.64 frystyk 51: PUBLIC int HTMaxRedirections = 10;      /* Max number of redirections */
 52: PUBLIC BOOL HTEnableFrom = NO;            /* Enable From header? */
1.71 frystyk 53: PUBLIC char * HTProxyHeaders = NULL;        /* Headers to pass as-is */
1.23 luotonen 54: 
1.59 frystyk 55: /* Type definitions and global variables etc. local to this module */
 56: /* This is the local definition of HTRequest->net_info */
 57: typedef enum _HTTPState {
1.71 frystyk 58:   HTTP_ERROR     = -3,
 59:   HTTP_NO_DATA    = -2,
 60:   HTTP_GOT_DATA   = -1,
 61:   HTTP_BEGIN     = 0,
 62:   HTTP_NEED_CONNECTION,
 63:   HTTP_NEED_REQUEST,
 64:   HTTP_SENT_REQUEST,
 65:   HTTP_NEED_BODY,
 66:   HTTP_REDIRECTION,
 67:   HTTP_AA
1.59 frystyk 68: } HTTPState;
1.55 frystyk 69: 
 70: typedef struct _http_info {
1.78 frystyk 71:   SOCKFD       sockfd;             /* Socket descripter */
1.71 frystyk 72:   SockA       sock_addr;       /* SockA is defined in tcp.h */
1.68 frystyk 73:   HTInputSocket *  isoc;                /* Input buffer */
1.71 frystyk 74:   HTStream *     target;               /* Output stream */
 75:   HTChunk *     transmit;             /* Line to be send */
 76:   int        addressCount;    /* Attempts if multi-homed host */
 77:   time_t       connecttime;       /* Used on multihomed hosts */
 78:   struct _HTRequest *    request;      /* Link back to request structure */
1.68 frystyk 79: 
 80:   HTTPState     state;          /* State of the connection */
1.55 frystyk 81: } http_info;
 82: 
1.71 frystyk 83: #define MAX_STATUS_LEN     150    /* Max number of chars to look at */
1.55 frystyk 84: 
1.71 frystyk 85: struct _HTStream {
 86:   CONST HTStreamClass *   isa;
 87:   HTStream *         target;
 88:   HTRequest *            request;
 89:   http_info *            http;
 90:   int                cnt;
 91:   HTSocketEOL            state;
 92:   BOOL            transparent;
1.79 frystyk 93:   double           version;         /* @@@ DOESN'T WORK */
1.71 frystyk 94:   int                status;
 95:   char            buffer[MAX_STATUS_LEN+1];
 96:   char *           bufptr;
 97: };
1.21 luotonen 98: 
1.79.2.1! cbrooks 99: PRIVATE PFPC HTUserHeaderFunc = 0 ;
 ! 100: 
1.71 frystyk 101: /* ------------------------------------------------------------------------- */
 102: /*                Help Functions               */
 103: /* ------------------------------------------------------------------------- */
1.21 luotonen 104: 
1.71 frystyk 105: /*                                 HTTPCleanup
1.1 timbl 106: **
1.55 frystyk 107: **   This function closes the connection and frees memory.
1.1 timbl 108: **
1.55 frystyk 109: **   Returns 0 on OK, else -1
1.1 timbl 110: */
1.71 frystyk 111: PRIVATE int HTTPCleanup ARGS1(HTRequest *, request)
1.1 timbl 112: {
1.71 frystyk 113:   http_info *http;
1.55 frystyk 114:   int status = 0;
1.71 frystyk 115:   if (!request || !request->net_info) {
1.78 frystyk 116:    if (PROT_TRACE) fprintf(TDEST, "HTTPCleanup. Bad argument!\n");
1.55 frystyk 117:    status = -1;
 118:   } else {
1.71 frystyk 119:    http = (http_info *) request->net_info;
1.78 frystyk 120:    if (http->sockfd != INVSOC) {
 121:      if (PROT_TRACE)
 122:        fprintf(TDEST,"HTTP........ Closing socket %d\n",http->sockfd);
1.59 frystyk 123:      if ((status = NETCLOSE(http->sockfd)) < 0)
1.78 frystyk 124:        HTErrorSysAdd(http->request, ERR_FATAL, socerrno, NO,
 125:               "NETCLOSE");
1.79.2.1! cbrooks 126:      HTEventThreadState( http->sockfd, THD_CLOSE) ;
 ! 127: /*     HTEventThreadState(http->sockfd, THD_CLOSE); */
 ! 128:      HTEventThread_clear( (void *)http ) ;
 ! 129: /*     HTThread_clear((HTNetInfo *) http); */
1.78 frystyk 130:      http->sockfd = INVSOC;
1.71 frystyk 131:    }
 132:    if (http->isoc)
 133:      HTInputSocket_free(http->isoc);
 134:    if (http->transmit)
 135:      HTChunkFree(http->transmit);
1.55 frystyk 136:   } 
 137:   free(http);
1.71 frystyk 138:   request->net_info = NULL;
1.55 frystyk 139:   return status;
 140: }
1.36 frystyk 141: 
1.23 luotonen 142: 
1.55 frystyk 143: /*                               HTTPSendRequest
 144: **
 145: **   This function composes and sends a request to the connected server
 146: **   specified.
 147: **
1.71 frystyk 148: **   Returns     <0       Error has occured or interrupted
 149: **           HT_WOULD_BLOCK if operation would have blocked
 150: **           HT_INTERRUPTED if interrupted
 151: **
 152: **   Note: The function does NEVER close the connection
1.1 timbl 153: */
1.55 frystyk 154: PRIVATE int HTTPSendRequest ARGS3(HTRequest *, request,
 155:                 http_info *, http, char *, url)
 156: {
 157:   int status = 0;
1.1 timbl 158: 
1.71 frystyk 159:   /* If first time through then generate HTTP request */
 160:   if (!http->transmit) {
 161:    HTChunk *command = HTChunkCreate(2048);
 162:    http->transmit = command;
 163:    if (request->method != METHOD_INVALID) {
 164:      HTChunkPuts(command, HTMethod_name(request->method));
 165:      HTChunkPutc(command, ' ');
 166:    }
1.21 luotonen 167:    else
1.71 frystyk 168:      HTChunkPuts(command, "GET ");
 169:    
 170:    /* if we are using a proxy gateway don't copy in the first slash
 171:     ** of say: /gopher://a;lkdjfl;ajdf;lkj/;aldk/adflj
 172:     ** so that just gohper://.... is sent. */
 173:    {
 174:      char *p1 = HTParse(url, "", PARSE_PATH|PARSE_PUNCTUATION);
 175:      if (using_proxy)
 176:        HTChunkPuts(command, p1+1);
 177:      else
 178:        HTChunkPuts(command, p1);
 179:      free(p1);
 180:    }
1.55 frystyk 181:    HTChunkPutc(command, ' ');
 182:    HTChunkPuts(command, HTTP_VERSION);
1.71 frystyk 183:    HTChunkPutc(command, CR);          /* CR LF, as in rfc 977 */
 184:    HTChunkPutc(command, LF);
 185:    
 186:    if (HTImProxy && HTProxyHeaders) {
 187:      HTChunkPuts(command, HTProxyHeaders);
 188:    } else {
 189:      char line[256];  /*@@@@ */
 190:      
 191:      /* If no conversion list, then put it up, but leave initialization
 192:        to the client */
 193:      if (!HTConversions)
 194:        HTConversions = HTList_new();
1.34 frystyk 195:      
1.71 frystyk 196:      /* Run through both lists and generate `accept' lines */
 197:      {
 198:        int i;
 199:        HTList *conversions[2];
 200:        conversions[0] = HTConversions;
 201:        conversions[1] = request->conversions;
 202:        
 203:        for (i=0; i<2; i++) {
 204:          HTList *cur = conversions[i];
 205:          HTPresentation *pres;
 206:          while ((pres =(HTPresentation *) HTList_nextObject(cur))) {
 207:            if (pres->rep_out == WWW_PRESENT) {
 208:              if (pres->quality != 1.0) {
 209:                sprintf(line, "Accept: %s; q=%.3f%c%c",
 210:                    HTAtom_name(pres->rep),
 211:                    pres->quality, CR, LF);
 212:              } else {
 213:                sprintf(line, "Accept: %s%c%c",
 214:                    HTAtom_name(pres->rep), CR, LF);
 215:              }
 216:              HTChunkPuts(command, line);
1.21 luotonen 217:            }
1.17 timbl 218:          }
 219:        }
1.2 timbl 220:      }
1.71 frystyk 221:      
 222:      /* Put out referer field if any parent */
 223:      if (request->parentAnchor) {
 224:        char *me = HTAnchor_address((HTAnchor *) request->anchor);
 225:        char *parent = HTAnchor_address((HTAnchor *)
 226:                        request->parentAnchor);
 227:        char *relative = HTParse(parent, me,
 228:                     PARSE_ACCESS|PARSE_HOST|PARSE_PATH|PARSE_PUNCTUATION);
 229:        if (relative && *relative) {
 230:          sprintf(line, "Referer: %s%c%c", parent, CR, LF);
 231:          HTChunkPuts(command, line);
 232:        }
 233:        free(me);
 234:        free(parent);
 235:        free(relative);
 236:      }
 237:      
 238:      /* Put out from field if enabled by client */
 239:      if (HTEnableFrom) {
 240:        CONST char *mailaddress = HTGetMailAddress();
 241:        if (mailaddress != NULL) {
 242:          sprintf(line, "From: %s%c%c", mailaddress, CR, LF);
 243:          HTChunkPuts(command, line);
 244:        }
 245:      }
 246:      
 247:      /* Put out user-agent */
 248:      sprintf(line, "User-Agent: %s/%s libwww/%s%c%c",
 249:          HTAppName ? HTAppName : "unknown",
 250:          HTAppVersion ? HTAppVersion : "0.0",
 251:          HTLibraryVersion, CR, LF);
 252:      HTChunkPuts(command, line);
 253:      
 254:      /* Put out authorization */
 255:      if (request->authorization != NULL) {
 256:        HTChunkPuts(command, "Authorization: ");
 257:        HTChunkPuts(command, request->authorization);
 258:        HTChunkPutc(command, CR);
 259:        HTChunkPutc(command, LF);
1.63 frystyk 260:      }
 261:    }
1.79.2.1! cbrooks 262:    { 
 ! 263:      /*
 ! 264:       * CLB 4-14-95 did user request special processing?
 ! 265:       */
 ! 266:      if (HTUserHeaderFunc) 
 ! 267:        HTChunkPuts(command, (*HTUserHeaderFunc)());
 ! 268:    }
1.71 frystyk 269:    HTChunkPutc(command, CR);         /* Blank line means "end" */
 270:    HTChunkPutc(command, LF);
 271:    HTChunkTerminate(command);
1.78 frystyk 272:    if (PROT_TRACE) fprintf(TDEST, "HTTP Tx..... %s", command->data);
1.71 frystyk 273:    
 274:    /* Translate into ASCII if necessary */
1.4 timbl 275: #ifdef NOT_ASCII
1.71 frystyk 276:    {
 277:      char * p;
 278:      for(p = command->data; *p; p++) {
 279:        *p = TOASCII(*p);
 280:      }
1.1 timbl 281:    }
1.71 frystyk 282: #endif
1.55 frystyk 283:   }
1.71 frystyk 284: 
 285:   /* Now, we are ready for sending the request */
 286:   status = NETWRITE(http->sockfd, http->transmit->data,
 287:           http->transmit->size-1);
 288:   if (status < 0) {
 289: #ifdef EAGAIN
1.78 frystyk 290:    if (socerrno == EAGAIN || socerrno == EWOULDBLOCK) 
1.71 frystyk 291: #else
1.78 frystyk 292:    if (socerrno == EWOULDBLOCK)
1.3 timbl 293: #endif
1.71 frystyk 294:    {
 295:      if (PROT_TRACE)
1.78 frystyk 296:        fprintf(TDEST, "HTTP Tx..... Write operation would block\n");
1.79.2.1! cbrooks 297:      HTEventThreadState(http->sockfd, THD_SET_WRITE);
1.71 frystyk 298:      return HT_WOULD_BLOCK;
 299:    } else {                 /* A real error has occured */
1.55 frystyk 300:      char *unescaped = NULL;
1.78 frystyk 301:      HTErrorSysAdd(request, ERR_FATAL, socerrno, NO, "NETWRITE");
1.55 frystyk 302:      StrAllocCopy(unescaped, url);
 303:      HTUnEscape(unescaped);
 304:      HTErrorAdd(request, ERR_FATAL, NO, HTERR_INTERNAL,
 305:            (void *) unescaped, (int) strlen(unescaped),
 306:            "HTTPSendRequest");
 307:      free(unescaped);
1.71 frystyk 308:      return -1;
1.55 frystyk 309:    }
 310:   }
1.79.2.1! cbrooks 311:   HTEventThreadState(http->sockfd, THD_CLR_WRITE);          /* Write OK */
1.55 frystyk 312:   return status;
 313: }
 314: 
 315: 
1.71 frystyk 316: PRIVATE BOOL HTTPAuthentication ARGS1(HTRequest *, request)
 317: {
 318:   HTAAScheme scheme;
 319:   HTList *valid_schemes = HTList_new();
 320:   HTAssocList **scheme_specifics = NULL;
1.76 frystyk 321:   char *tmplate = NULL;
1.71 frystyk 322: 
 323:   if (request->WWWAAScheme) {
 324:    if ((scheme = HTAAScheme_enum(request->WWWAAScheme)) != HTAA_UNKNOWN) {
 325:      HTList_addObject(valid_schemes, (void *) scheme);
 326:      if (!scheme_specifics) {
 327:        int i;
 328:        scheme_specifics = (HTAssocList**)
 329:          malloc(HTAA_MAX_SCHEMES * sizeof(HTAssocList*));
 330:        if (!scheme_specifics)
 331:          outofmem(__FILE__, "HTTPAuthentication");
 332:        for (i=0; i < HTAA_MAX_SCHEMES; i++)
 333:          scheme_specifics[i] = NULL;
 334:      }
 335:      scheme_specifics[scheme] = HTAA_parseArgList(request->WWWAARealm);
 336:    } else if (PROT_TRACE) {
 337:      HTErrorAdd(request, ERR_INFO, NO, HTERR_UNKNOWN_AA,
 338:            (void *) request->WWWAAScheme, 0, "HTTPAuthentication");
 339:      return NO;
 340:    }
 341:   }
 342:   if (request->WWWprotection) {
 343:    if (PROT_TRACE)
1.78 frystyk 344:      fprintf(TDEST, "Protection template set to `%s'\n",
1.71 frystyk 345:          request->WWWprotection);
1.76 frystyk 346:    StrAllocCopy(tmplate, request->WWWprotection);
1.71 frystyk 347:   }
 348:   request->valid_schemes = valid_schemes;
 349:   request->scheme_specifics = scheme_specifics;
1.76 frystyk 350:   request->prot_template = tmplate;
1.71 frystyk 351:   return YES;
 352: }
 353: 
 354: 
 355: /*
 356: **   This is a big switch handling all HTTP return codes. It puts in any
 357: **   appropiate error message and decides whether we should expect data
1.78 frystyk 358: **   or not.
1.55 frystyk 359: */
1.71 frystyk 360: PRIVATE void HTTPResponse ARGS1(HTStream *, me)
1.55 frystyk 361: {
1.71 frystyk 362:   switch (me->status) {
 363: 
1.78 frystyk 364:    case 0:                        /* 0.9 response */
 365:    case 200:
 366:    case 201:
 367:    case 202:
 368:    case 203:
 369:    case 205:
 370:    case 206:
1.71 frystyk 371:    break;
1.78 frystyk 372: 
 373:    case 204:                           /* No Response */
 374:    me->http->state = HTTP_NO_DATA;
1.71 frystyk 375:    break;
1.78 frystyk 376: 
1.71 frystyk 377:    case 301:                              /* Moved */
 378:    case 302:                              /* Found */
 379:    me->http->state = HTTP_REDIRECTION;
 380:    break;
1.55 frystyk 381:    
1.71 frystyk 382:    case 303:                              /* Method */
 383:    HTAlert("This client doesn't support automatic redirection of type `Method'");
 384:    me->http->state = HTTP_ERROR;
 385:    break;
1.55 frystyk 386:    
1.78 frystyk 387:    case 400:                           /* Bad Request */
 388:    HTErrorAdd(me->request, ERR_FATAL, NO, HTERR_BAD_REQUEST,
 389:          NULL, 0, "HTLoadHTTP");
1.71 frystyk 390:    me->http->state = HTTP_ERROR;
 391:    break;
1.70 howcome 392: 
1.71 frystyk 393:    case 401:
1.78 frystyk 394:    HTErrorAdd(me->request, ERR_FATAL, NO, HTERR_UNAUTHORIZED,
 395:          NULL, 0, "HTLoadHTTP");
1.71 frystyk 396:    me->http->state = HTTP_AA;
 397:    break;
 398:    
 399:    case 402:                         /* Payment required */
1.78 frystyk 400:    HTErrorAdd(me->request, ERR_FATAL, NO, HTERR_PAYMENT_REQUIRED,
 401:          NULL, 0, "HTLoadHTTP");
 402:    me->http->state = HTTP_ERROR;
1.71 frystyk 403:    break;
1.55 frystyk 404:    
1.71 frystyk 405:    case 403:                            /* Forbidden */
1.78 frystyk 406:    HTErrorAdd(me->request, ERR_FATAL, NO, HTERR_FORBIDDEN,
 407:          NULL, 0, "HTLoadHTTP");
1.71 frystyk 408:    me->http->state = HTTP_ERROR;
 409:    break;
1.55 frystyk 410:    
1.71 frystyk 411:    case 404:                            /* Not Found */
1.78 frystyk 412:    HTErrorAdd(me->request, ERR_FATAL, NO, HTERR_NOT_FOUND,
 413:          NULL, 0, "HTLoadHTTP");
1.71 frystyk 414:    me->http->state = HTTP_ERROR;
 415:    break;
 416:    
1.78 frystyk 417:    case 405:                           /* Not Allowed */
 418:    HTErrorAdd(me->request, ERR_FATAL, NO, HTERR_NOT_ALLOWED,
 419:          NULL, 0, "HTLoadHTTP");
 420:    me->http->state = HTTP_ERROR;
 421:    break;
 422: 
 423:    case 406:                         /* None Acceptable */
 424:    HTErrorAdd(me->request, ERR_FATAL, NO, HTERR_NONE_ACCEPTABLE,
 425:          NULL, 0, "HTLoadHTTP");
 426:    me->http->state = HTTP_ERROR;
 427:    break;
 428: 
 429:    case 407:                  /* Proxy Authentication Required */
 430:    HTErrorAdd(me->request, ERR_FATAL, NO, HTERR_PROXY,
 431:          NULL, 0, "HTLoadHTTP");
 432:    me->http->state = HTTP_ERROR;
 433:    break;
 434: 
 435:    case 408:                         /* Request Timeout */
 436:    HTErrorAdd(me->request, ERR_FATAL, NO, HTERR_TIMEOUT,
 437:          NULL, 0, "HTLoadHTTP");
 438:    me->http->state = HTTP_ERROR;
 439:    break;
 440: 
1.71 frystyk 441:    case 500:
1.78 frystyk 442:    HTErrorAdd(me->request, ERR_FATAL, NO, HTERR_INTERNAL,
 443:          NULL, 0, "HTLoadHTTP");
 444:    me->http->state = HTTP_ERROR;
 445:    break;
 446:    
1.71 frystyk 447:    case 501:
1.78 frystyk 448:    HTErrorAdd(me->request, ERR_FATAL, NO, HTERR_NOT_IMPLEMENTED,
 449:          NULL, 0, "HTLoadHTTP");
 450:    me->http->state = HTTP_ERROR;
 451:    break;
 452: 
 453:    case 502:
 454:    HTErrorAdd(me->request, ERR_FATAL, NO, HTERR_BAD_GATE,
 455:          NULL, 0, "HTLoadHTTP");
 456:    me->http->state = HTTP_ERROR;
 457:    break;
 458: 
 459:    case 503:
 460:    HTErrorAdd(me->request, ERR_FATAL, NO, HTERR_DOWN,
 461:          NULL, 0, "HTLoadHTTP");
 462:    me->http->state = HTTP_ERROR;
 463:    break;
 464: 
 465:    case 504:
 466:    HTErrorAdd(me->request, ERR_FATAL, NO, HTERR_GATE_TIMEOUT,
 467:          NULL, 0, "HTLoadHTTP");
1.71 frystyk 468:    me->http->state = HTTP_ERROR;
 469:    break;
1.78 frystyk 470: 
1.71 frystyk 471:    default:                        /* bad number */
 472:    HTErrorAdd(me->request, ERR_FATAL, NO, HTERR_BAD_REPLY,
 473:          (void *) me->buffer, me->cnt, "HTLoadHTTP");
 474:    me->http->state = HTTP_ERROR;
 475:    break;
1.55 frystyk 476:   }
 477: }
 478: 
1.71 frystyk 479: /* ------------------------------------------------------------------------- */
 480: /*             HTTP Status Line Stream             */
 481: /* ------------------------------------------------------------------------- */
1.55 frystyk 482: 
1.71 frystyk 483: /*
 484: **   Analyse the string we have read. If it is a HTTP 1.0 or higher
 485: **   then create a MIME-stream, else create a Guess stream to find out
 486: **   what the 0.9 server is sending. We need to copy the buffer as we don't
 487: **   know if we can modify the contents or not.
1.78 frystyk 488: **
 489: **   Stream handling is a function of the status code returned from the 
 490: **   server:
 491: **       200:   Use `output_stream' in HTRequest structure
 492: **       else:  Use `output_flush' in HTRequest structure
1.56 frystyk 493: */
1.71 frystyk 494: PRIVATE void flush ARGS1(HTStream *, me)
1.56 frystyk 495: {
1.71 frystyk 496:   HTRequest *req = me->request;
 497:   me->transparent = YES;               /* Only do this once */
 498:   if (me->state == EOL_FLF) {
 499:    if (strncasecomp(me->buffer, "http/", 5) ||
1.79 frystyk 500:      sscanf(me->buffer+5, "%lf %d", &me->version, &me->status) < 2) {
1.71 frystyk 501:      HTErrorAdd(req, ERR_INFO, NO, HTERR_HTTP09,
 502:            (void *) me->buffer, me->cnt, "HTTPStatusStream");
 503:      me->target = HTGuess_new(req, NULL, WWW_UNKNOWN,
 504:                   req->output_format, req->output_stream);
 505:      PUTBLOCK(me->buffer, me->cnt);
 506:    } else {
 507:      if (req->output_format == WWW_SOURCE) {
 508:        me->target = HTMIMEConvert(req, NULL, WWW_MIME,
 509:                      req->output_format,
 510:                      req->output_stream);
1.78 frystyk 511:      } else if (me->status==200 && req->method==METHOD_GET) {
 512:        HTStream *s;
 513: 
1.71 frystyk 514:        me->target = HTStreamStack(WWW_MIME,req->output_format,
1.78 frystyk 515:                      req->output_stream, req, NO);
 516: 
 517:        /* Cache HTTP 1.0 responses */
 518:        /* howcome added test for return value from HTCacheWriter 12/1/95 */
 519: 
 520:        if (HTCacheDir && (s = HTCacheWriter(req, NULL, WWW_MIME,
 521:                            req->output_format,
 522:                            req->output_stream)))
 523:          {
 524:            me->target = HTTee(me->target, s);
 525:          }
1.71 frystyk 526:      } else {
 527:        me->target = HTMIMEConvert(req, NULL, WWW_MIME,
1.78 frystyk 528:                      WWW_SOURCE, req->output_flush ?
 529:                      req->output_flush : HTBlackHole());
1.56 frystyk 530:      }
1.78 frystyk 531:      if (!me->target)
1.71 frystyk 532:        me->target = HTBlackHole();           /* What else */
1.56 frystyk 533:    }
1.71 frystyk 534:   } else {
 535:    me->target = HTGuess_new(req, NULL, WWW_UNKNOWN, req->output_format,
 536:                 req->output_stream);
 537:    PUTBLOCK(me->buffer, me->cnt);
1.56 frystyk 538:   }
1.71 frystyk 539: }
1.56 frystyk 540: 
1.71 frystyk 541: PRIVATE void HTTPStatus_put_character ARGS2(HTStream *, me, char, c)
 542: {
 543:   if (me->transparent)
 544:    PUTC(c);
 545:   else {
 546:    if (me->state == EOL_FCR) {
 547:      if (c == LF) {
 548:        me->state = EOL_FLF;              /* Line found */
 549:        flush(me);
 550:      } else {
 551:        me->state = EOL_BEGIN;
 552:        me->cnt += 2;
 553:        *me->bufptr++ = CR;          /* Need to put it back */
 554:        *me->bufptr++ = c;
 555:      }
 556:    } else if (c == CR) {
 557:      me->state = EOL_FCR;
 558:    } else if (c == LF) {
 559:      me->state = EOL_FLF;                /* Line found */
 560:      me->cnt++;
 561:      *me->bufptr++ = LF;
 562:      flush(me);
 563:    } else {
 564:      me->cnt++;
 565:      *me->bufptr++ = c;
 566:      if (me->cnt >= MAX_STATUS_LEN)
 567:        flush(me);
 568:    }
1.56 frystyk 569:   }
 570: }
 571: 
1.71 frystyk 572: PRIVATE void HTTPStatus_put_string ARGS2(HTStream *, me, CONST char*, s)
 573: {
 574:   while (!me->transparent && *s)
 575:    HTTPStatus_put_character(me, *s++);
 576:   if (*s) PUTS(s);
 577: }
1.56 frystyk 578: 
1.71 frystyk 579: PRIVATE void HTTPStatus_put_block ARGS3(HTStream *, me, CONST char*, b, int, l)
 580: {
 581:   while (!me->transparent && l-- > 0)
 582:    HTTPStatus_put_character(me, *b++);
 583:   if (l > 0) PUTBLOCK(b, l);
 584: }
 585: 
 586: PRIVATE int HTTPStatus_free ARGS1(HTStream *, me)
 587: {
 588:   int status = me->status;
1.78 frystyk 589:   HTTPResponse(me);                   /* Get next state */
1.71 frystyk 590:   if (!me->transparent)
 591:    flush(me);
 592:   if (me->target)
 593:    FREE_TARGET;
 594:   free(me);
 595:   return status;     /* Return the HTTP status value - 0 if HTTP 0.9 */
 596: }
 597: 
 598: PRIVATE int HTTPStatus_abort ARGS2(HTStream *, me, HTError, e)
 599: {
 600:   if (me->target)
1.74 frystyk 601:    ABORT_TARGET;
1.71 frystyk 602:   free(me);
1.74 frystyk 603:   if (PROT_TRACE)
1.78 frystyk 604:    fprintf(TDEST, "HTTPStatus.. ABORTING LOAD...\n");
1.71 frystyk 605:   return EOF;
 606: }
 607: 
 608: /*   HTTPStatus Stream
 609: **   -----------------
 610: */
 611: PRIVATE CONST HTStreamClass HTTPStatusClass =
 612: {       
 613:   "HTTPStatus",
 614:   HTTPStatus_free,
 615:   HTTPStatus_abort,
 616:   HTTPStatus_put_character,
 617:   HTTPStatus_put_string,
 618:   HTTPStatus_put_block
 619: };
 620: 
 621: PUBLIC HTStream * HTTPStatus_new ARGS2(HTRequest *, request,
 622:                    http_info *, http)
 623: {
 624:   HTStream * me = (HTStream *) calloc(1, sizeof(HTStream));
 625:   if (!me) outofmem(__FILE__, "HTTPStatus_new");
 626:   me->isa = &HTTPStatusClass;
 627:   me->request = request;
 628:   me->http = http;
 629:   me->bufptr = me->buffer;
 630:   me->state = EOL_BEGIN;
 631:   return me;
 632: }
 633: 
 634: /* ------------------------------------------------------------------------- */
 635: 
 636: /*       Load Document from HTTP Server            HTLoadHTTP
1.55 frystyk 637: **       ==============================
 638: **
 639: **   Given a hypertext address, this routine loads a document.
 640: **
 641: ** On entry,
 642: **   request        This is the request structure
 643: ** On exit,
1.71 frystyk 644: **   returns     <0       Error has occured or interrupted
 645: **           HT_WOULD_BLOCK if operation would have blocked
1.58 frystyk 646: **           HT_LOADED    if return status 200 OK
 647: **           HT_NO_DATA   if return status 204 No Response
1.55 frystyk 648: */
 649: PUBLIC int HTLoadHTTP ARGS1 (HTRequest *, request)
 650: {
1.71 frystyk 651:   int status = HT_ERROR;
 652:   char *url;              /* Gets initialized on every entry */
1.55 frystyk 653:   http_info *http;            /* Specific protocol information */
 654: 
 655:   if (!request || !request->anchor) {
1.78 frystyk 656:     if (PROT_TRACE) fprintf(TDEST, "HTLoadHTTP.. Bad argument\n");
1.71 frystyk 657:     return HT_ERROR;
1.55 frystyk 658:   }
 659:   url = HTAnchor_physical(request->anchor);
1.17 timbl 660:   
1.71 frystyk 661:   /* Only do the setup first time through. This is actually state HTTP_BEGIN
 662:    but it can't be in the state machine as we need the structure first */
 663:   if (!request->net_info) {
1.22 luotonen 664:    /*
1.71 frystyk 665:    ** Initiate a new http structure and bind to request structure
 666:    ** This is actually state HTTP_BEGIN, but it can't be in the state
 667:    ** machine as we need the structure first.
1.22 luotonen 668:    */
1.78 frystyk 669:    if (PROT_TRACE) fprintf(TDEST, "HTTP........ Looking for `%s\'\n", url);
1.71 frystyk 670:    if ((http = (http_info *) calloc(1, sizeof(http_info))) == NULL)
 671:      outofmem(__FILE__, "HTLoadHTTP");
1.78 frystyk 672:    http->sockfd = INVSOC;           /* Invalid socket number */
1.71 frystyk 673:    http->request = request;
 674:    http->state = HTTP_BEGIN;
 675:    request->net_info = (HTNetInfo *) http;
1.79.2.1! cbrooks 676:    HTEventThread_new( (void *)http ) ;
 ! 677: /*   HTThread_new((HTNetInfo *) http); */
1.71 frystyk 678:   } else
 679:    http = (http_info *) request->net_info;     /* Get existing copy */
 680: 
 681:   /* Now jump into the machine. We know the state from the previous run */
 682:   while (1) {
 683:    switch (http->state) {
 684:     case HTTP_BEGIN:
 685:      /*
 686:       ** Compose authorization information (this was moved here
 687:       ** from after the making of the connection so that the connection
 688:       ** wouldn't have to wait while prompting username and password
 689:       ** from the user).             -- AL 13.10.93
 690:       */
 691:      HTAA_composeAuth(request);
 692:      if (PROT_TRACE) {
 693:        if (request->authorization)
1.78 frystyk 694:          fprintf(TDEST, "HTTP........ Sending Authorization: %s\n",
1.71 frystyk 695:              request->authorization);
 696:        else
1.78 frystyk 697:          fprintf(TDEST,
1.71 frystyk 698:              "HTTP........ Not sending authorization (yet)\n");
 699:      }
 700:      http->state = HTTP_NEED_CONNECTION;
 701:      break;
 702:      
 703:     case HTTP_NEED_CONNECTION:    /* Now let's set up a connection */
 704:      status = HTDoConnect((HTNetInfo *) http, url, TCP_PORT,
 705:                 NULL, NO);
 706:      if (!status) {
 707:        if (PROT_TRACE)
1.78 frystyk 708:          fprintf(TDEST, "HTTP........ Connected, socket %d\n",
1.71 frystyk 709:              http->sockfd);
 710:        http->isoc = HTInputSocket_new(http->sockfd);
 711:        http->state = HTTP_NEED_REQUEST;
 712:      } else if (status == HT_WOULD_BLOCK)
 713:        return status;
 714:      else
 715:        http->state = HTTP_ERROR;       /* Error or interrupt */
 716:      break;
 717: 
 718:     case HTTP_NEED_REQUEST:     /* Compose the request and send it */
 719:      if ((status = HTTPSendRequest(request, http, url)) < 0) {
 720:        if (status == HT_WOULD_BLOCK)
1.55 frystyk 721:          return status;
1.71 frystyk 722:        else
 723:          http->state = HTTP_ERROR;
1.55 frystyk 724:      } else {
1.71 frystyk 725:        http->state = HTTP_SENT_REQUEST;      
1.21 luotonen 726:      }
1.71 frystyk 727:      break;
1.21 luotonen 728: 
1.78 frystyk 729:     case HTTP_SENT_REQUEST:              /* Put up stream */
 730:      http->target = HTImProxy ?
 731:        request->output_stream : HTTPStatus_new(request, http);
 732:      http->state = HTTP_NEED_BODY;
 733:      break;
 734: 
 735:     case HTTP_NEED_BODY:             /* Read the response */
1.74 frystyk 736:      status = HTInputSocket_read(http->isoc, http->target);
 737:      if (status == HT_WOULD_BLOCK)
1.71 frystyk 738:        return HT_WOULD_BLOCK;
1.75 frystyk 739:      else if (status == HT_INTERRUPTED) {
 740:        (*http->target->isa->abort)(http->target, NULL);
1.74 frystyk 741:        http->state = HTTP_ERROR;
1.78 frystyk 742:      } else if (status == HT_LOADED) {
1.75 frystyk 743:        (*http->target->isa->_free)(http->target);
 744:        if (http->state == HTTP_NEED_BODY)
 745:          http->state = HTTP_GOT_DATA;
1.78 frystyk 746:      } else {
 747:        (*http->target->isa->_free)(http->target);
 748:        http->state = HTTP_ERROR;
1.75 frystyk 749:      }
1.71 frystyk 750:      break;
 751: 
 752:      case HTTP_REDIRECTION:
 753:      if (request->redirect) {
 754:        HTAnchor *anchor;
 755:        if (status == 301) {
 756:          HTErrorAdd(request, ERR_INFO, NO, HTERR_MOVED,
 757:                (void *) request->redirect,
 758:                (int) strlen(request->redirect), "HTLoadHTTP");
 759:        } else if (status == 302) {
 760:          HTErrorAdd(request, ERR_INFO, NO, HTERR_FOUND,
 761:                (void *) request->redirect,
 762:                (int) strlen(request->redirect), "HTLoadHTTP");
1.55 frystyk 763:        }
1.71 frystyk 764:        anchor = HTAnchor_findAddress(request->redirect);
 765:        if (++request->redirections < HTMaxRedirections) {
 766:          HTTPCleanup(request);
 767:          return HTLoadAnchorRecursive((HTAnchor *) anchor, request);
 768:        } else {
 769:          HTErrorAdd(request, ERR_FATAL, NO, HTERR_MAX_REDIRECT,
1.58 frystyk 770:                NULL, 0, "HTLoadHTTP");
1.71 frystyk 771:          http->state = HTTP_ERROR;
1.58 frystyk 772:        }
1.71 frystyk 773:      } else {
 774:        HTErrorAdd(request, ERR_FATAL, NO, HTERR_BAD_REPLY,
 775:              NULL, 0, "HTLoadHTTP");
 776:        http->state = HTTP_ERROR;
 777:      }
 778:      break;
 779: 
 780:     case HTTP_AA:
 781:      if (HTTPAuthentication(request) == YES &&
 782:        HTAA_retryWithAuth(request) == YES) {
1.78 frystyk 783:        HTTPCleanup(request);
1.71 frystyk 784:        return HTLoadAnchor((HTAnchor *) request->anchor, request);
 785:      } else {
 786:        char *unescaped = NULL;
 787:        StrAllocCopy(unescaped, url);
 788:        HTUnEscape(unescaped);
 789:        HTErrorAdd(request, ERR_FATAL, NO, HTERR_UNAUTHORIZED,
 790:              (void *) unescaped,
 791:              (int) strlen(unescaped), "HTLoadHTTP");
 792:        free(unescaped);
1.78 frystyk 793:        http->state = HT_ERROR;
1.71 frystyk 794:      }
 795:      break;
 796: 
 797:     case HTTP_GOT_DATA:
1.74 frystyk 798:      HTTPCleanup(request);
1.71 frystyk 799:      return HT_LOADED;
 800:      break;
 801:      
 802:     case HTTP_NO_DATA:
 803:      HTTPCleanup(request);
 804:      return HT_NO_DATA;
 805:      break;
 806: 
 807:     case HTTP_ERROR:
 808:      HTTPCleanup(request);
 809:      return HT_ERROR;
 810:      break;
 811:    }
 812:   } /* End of while(1) */
 813: }  
1.79.2.1! cbrooks 814: 
 ! 815: /*
 ! 816: * HTAddUserHeader - 
 ! 817: * allow user to specify a function to add client defined 
 ! 818: * HTTP request headers. 
 ! 819: * NO VALIDATION is performed on these headers. In particular, each header
 ! 820: * MUST be terminated by a CR-LF pair 
 ! 821: */
 ! 822: 
 ! 823: PUBLIC PFPC HTAddUserHeader ARGS1( PFPC, userfunc)
 ! 824: {
 ! 825:   PFPC oldfunc = HTUserHeaderFunc ;
 ! 826:   HTUserHeaderFunc = userfunc;
 ! 827:   return oldfunc;
 ! 828: }
 ! 829: 
1.71 frystyk 830: 
 831: /* Protocol descriptor */
 832: 
 833: GLOBALDEF PUBLIC HTProtocol HTTP = {
 834:   "http", SOC_NON_BLOCK, HTLoadHTTP, NULL, NULL
 835: };
1.21 luotonen 836: 

Webmaster

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