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

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

Webmaster

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