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

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

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;
 309:   char *template = NULL;
 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);
 334:    StrAllocCopy(template, request->WWWprotection);
 335:   }
 336:   request->valid_schemes = valid_schemes;
 337:   request->scheme_specifics = scheme_specifics;
 338:   request->prot_template = template;
 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
 346: **   or not. If we are not interested in the body (for example in 3xx
 347: **   codes) then turn the stream into a black hole.
1.55 frystyk 348: */
1.71 frystyk 349: PRIVATE void HTTPResponse ARGS1(HTStream *, me)
1.55 frystyk 350: {
1.71 frystyk 351:   char *url = HTAnchor_physical(me->request->anchor);
 352:   switch (me->status) {
 353: 
 354:    case 204:                           /* No response */
 355:    HTErrorAdd(me->request, ERR_INFO, NO, HTERR_NO_RESPONSE,
 356:          NULL, 0, "HTLoadHTTP");
 357:    me->http->state = HTTP_NO_DATA; 
 358:    break;
 359:    
 360:    case 203:                             /* Partial */
 361:    HTErrorAdd(me->request, ERR_INFO, NO, HTERR_PARTIAL,
 362:          NULL, 0, "HTLoadHTTP");
 363:    /* Drop through to 200 to get the body */
 364:    
 365:    case 200:
 366:    me->http->state = HTTP_NEED_BODY;
 367:    break;
 368:    
 369:    case 301:                              /* Moved */
 370:    case 302:                              /* Found */
 371:    me->http->state = HTTP_REDIRECTION;
 372:    break;
1.55 frystyk 373:    
1.71 frystyk 374:    case 303:                              /* Method */
 375:    HTAlert("This client doesn't support automatic redirection of type `Method'");
 376:    me->http->state = HTTP_ERROR;
 377:    break;
1.55 frystyk 378:    
1.71 frystyk 379:    case 304:                        /* Not modified Since */
 380:    {
 381:      char *unescaped = NULL;
 382:      StrAllocCopy(unescaped, url);
 383:      HTUnEscape(unescaped);
 384:      HTErrorAdd(me->request, ERR_INFO, NO, HTERR_NOT_MODIFIED,
 385:            (void *) unescaped, (int) strlen(unescaped),
 386:            "HTLoadHTTP");
 387:      free(unescaped);
 388:    }
 389:    me->http->state = HTTP_NO_DATA;
 390:    break;
 391:    
 392:    case 400:                         /* Bad me->request */
 393:    {
 394:      char *unescaped = NULL;
 395:      StrAllocCopy(unescaped, url);
 396:      HTUnEscape(unescaped);
 397:      HTErrorAdd(me->request, ERR_FATAL, NO, HTERR_BAD_REQUEST,
 398:            (void *) unescaped, (int) strlen(unescaped),
 399:            "HTLoadHTTP");
 400:      free(unescaped);
 401:    }
 402:    me->http->state = HTTP_ERROR;
 403:    break;
1.70 howcome 404: 
1.71 frystyk 405:    case 401:
 406:    me->http->state = HTTP_AA;
 407:    break;
 408:    
 409:    case 402:                         /* Payment required */
 410:    {
 411:      char *unescaped = NULL;
 412:      StrAllocCopy(unescaped, url);
 413:      HTUnEscape(unescaped);
 414:      HTErrorAdd(me->request, ERR_FATAL, NO,
 415:            HTERR_PAYMENT_REQUIRED, (void *) unescaped,
 416:            (int) strlen(unescaped), "HTLoadHTTP");
 417:      free(unescaped);
1.17 timbl 418:    }
1.71 frystyk 419:    me->http->state = HTTP_NO_DATA;
 420:    break;
1.55 frystyk 421:    
1.71 frystyk 422:    case 403:                            /* Forbidden */
 423:    {
 424:      char *unescaped = NULL;
 425:      StrAllocCopy(unescaped, url);
 426:      HTUnEscape(unescaped);
 427:      HTErrorAdd(me->request, ERR_FATAL, NO, HTERR_FORBIDDEN,
 428:            (void *) unescaped, (int) strlen(unescaped),
 429:            "HTLoadHTTP");
 430:      free(unescaped);
 431:    }
 432:    me->http->state = HTTP_ERROR;
 433:    break;
1.55 frystyk 434:    
1.71 frystyk 435:    case 404:                            /* Not Found */
 436:    {
 437:      char *unescaped = NULL;
 438:      StrAllocCopy(unescaped, url);
 439:      HTUnEscape(unescaped);
 440:      HTErrorAdd(me->request, ERR_FATAL, NO, HTERR_NOT_FOUND,
 441:            (void *) unescaped, (int) strlen(unescaped),
 442:            "HTLoadHTTP");
 443:      free(unescaped);
 444:    }
 445:    me->http->state = HTTP_ERROR;
 446:    break;
 447:    
 448:    case 500:
 449:    case 501:
 450:    {
 451:      char *unescaped = NULL;
 452:      StrAllocCopy(unescaped, url);
 453:      HTUnEscape(unescaped);
 454:      HTErrorAdd(me->request, ERR_FATAL, NO, HTERR_INTERNAL,
 455:            (void *) unescaped, (int) strlen(unescaped),
 456:            "HTLoadHTTP");
 457:      free(unescaped);
 458:    }
 459:    me->http->state = HTTP_ERROR;
 460:    break;
 461:    
 462:    default:                        /* bad number */
 463:    HTErrorAdd(me->request, ERR_FATAL, NO, HTERR_BAD_REPLY,
 464:          (void *) me->buffer, me->cnt, "HTLoadHTTP");
 465:    me->http->state = HTTP_ERROR;
 466:    break;
1.55 frystyk 467:   }
 468: }
 469: 
1.71 frystyk 470: /* ------------------------------------------------------------------------- */
 471: /*             HTTP Status Line Stream             */
 472: /* ------------------------------------------------------------------------- */
1.55 frystyk 473: 
1.71 frystyk 474: /*
 475: **   Analyse the string we have read. If it is a HTTP 1.0 or higher
 476: **   then create a MIME-stream, else create a Guess stream to find out
 477: **   what the 0.9 server is sending. We need to copy the buffer as we don't
 478: **   know if we can modify the contents or not.
1.56 frystyk 479: */
1.71 frystyk 480: PRIVATE void flush ARGS1(HTStream *, me)
1.56 frystyk 481: {
1.71 frystyk 482:   HTRequest *req = me->request;
 483:   me->transparent = YES;               /* Only do this once */
 484:   if (me->state == EOL_FLF) {
 485:    if (strncasecomp(me->buffer, "http/", 5) ||
 486:      sscanf(me->buffer+5, "%f %d", &me->version, &me->status) < 2) {
 487:      HTErrorAdd(req, ERR_INFO, NO, HTERR_HTTP09,
 488:            (void *) me->buffer, me->cnt, "HTTPStatusStream");
 489:      me->target = HTGuess_new(req, NULL, WWW_UNKNOWN,
 490:                   req->output_format, req->output_stream);
 491:      PUTBLOCK(me->buffer, me->cnt);
 492:    } else {
 493:      HTTPResponse(me);               /* Get next state */
 494:      if (req->output_format == WWW_SOURCE) {
 495:        me->target = HTMIMEConvert(req, NULL, WWW_MIME,
 496:                      req->output_format,
 497:                      req->output_stream);
 498:      } else if (me->http->state == HTTP_NEED_BODY) {
 499:        me->target = HTStreamStack(WWW_MIME,req->output_format,
 500:                      req->output_stream,
 501:                      req, NO);
 502:        if (HTCacheDir) {        /* Cache HTTP 1.0 responses */
 503:          me->target =
 504:            HTTee(me->target,
 505:               HTCacheWriter(req, NULL, WWW_MIME,
 506:                      req->output_format,
 507:                      req->output_stream));
1.56 frystyk 508:        }
1.71 frystyk 509:      } else {
 510:        me->target = HTMIMEConvert(req, NULL, WWW_MIME,
 511:                      WWW_SOURCE, HTBlackHole());
1.56 frystyk 512:      }
1.71 frystyk 513:      if (!me->target) {
 514:        if (PROT_TRACE)
 515:          fprintf(stderr, "HTTPStream.. Using a black hole\n");
 516:        me->target = HTBlackHole();           /* What else */
 517:      }      
1.56 frystyk 518:    }
1.71 frystyk 519:   } else {
 520:    me->target = HTGuess_new(req, NULL, WWW_UNKNOWN, req->output_format,
 521:                 req->output_stream);
 522:    PUTBLOCK(me->buffer, me->cnt);
1.56 frystyk 523:   }
1.71 frystyk 524: }
1.56 frystyk 525: 
1.71 frystyk 526: PRIVATE void HTTPStatus_put_character ARGS2(HTStream *, me, char, c)
 527: {
 528:   if (me->transparent)
 529:    PUTC(c);
 530:   else {
 531:    if (me->state == EOL_FCR) {
 532:      if (c == LF) {
 533:        me->state = EOL_FLF;              /* Line found */
 534:        flush(me);
 535:      } else {
 536:        me->state = EOL_BEGIN;
 537:        me->cnt += 2;
 538:        *me->bufptr++ = CR;          /* Need to put it back */
 539:        *me->bufptr++ = c;
 540:      }
 541:    } else if (c == CR) {
 542:      me->state = EOL_FCR;
 543:    } else if (c == LF) {
 544:      me->state = EOL_FLF;                /* Line found */
 545:      me->cnt++;
 546:      *me->bufptr++ = LF;
 547:      flush(me);
 548:    } else {
 549:      me->cnt++;
 550:      *me->bufptr++ = c;
 551:      if (me->cnt >= MAX_STATUS_LEN)
 552:        flush(me);
 553:    }
1.56 frystyk 554:   }
 555: }
 556: 
1.71 frystyk 557: PRIVATE void HTTPStatus_put_string ARGS2(HTStream *, me, CONST char*, s)
 558: {
 559:   while (!me->transparent && *s)
 560:    HTTPStatus_put_character(me, *s++);
 561:   if (*s) PUTS(s);
 562: }
1.56 frystyk 563: 
1.71 frystyk 564: PRIVATE void HTTPStatus_put_block ARGS3(HTStream *, me, CONST char*, b, int, l)
 565: {
 566:   while (!me->transparent && l-- > 0)
 567:    HTTPStatus_put_character(me, *b++);
 568:   if (l > 0) PUTBLOCK(b, l);
 569: }
 570: 
 571: PRIVATE int HTTPStatus_free ARGS1(HTStream *, me)
 572: {
 573:   int status = me->status;
 574:   if (!me->transparent)
 575:    flush(me);
 576:   if (me->target)
 577:    FREE_TARGET;
 578:   free(me);
 579:   return status;     /* Return the HTTP status value - 0 if HTTP 0.9 */
 580: }
 581: 
 582: PRIVATE int HTTPStatus_abort ARGS2(HTStream *, me, HTError, e)
 583: {
 584:   if (me->target)
1.74 ! frystyk 585:    ABORT_TARGET;
1.71 frystyk 586:   free(me);
1.74 ! frystyk 587:   if (PROT_TRACE)
 ! 588:    fprintf(stderr, "HTTPStatus.. ABORTING LOAD...\n");
1.71 frystyk 589:   return EOF;
 590: }
 591: 
 592: /*   HTTPStatus Stream
 593: **   -----------------
 594: */
 595: PRIVATE CONST HTStreamClass HTTPStatusClass =
 596: {       
 597:   "HTTPStatus",
 598:   HTTPStatus_free,
 599:   HTTPStatus_abort,
 600:   HTTPStatus_put_character,
 601:   HTTPStatus_put_string,
 602:   HTTPStatus_put_block
 603: };
 604: 
 605: PUBLIC HTStream * HTTPStatus_new ARGS2(HTRequest *, request,
 606:                    http_info *, http)
 607: {
 608:   HTStream * me = (HTStream *) calloc(1, sizeof(HTStream));
 609:   if (!me) outofmem(__FILE__, "HTTPStatus_new");
 610:   me->isa = &HTTPStatusClass;
 611:   me->request = request;
 612:   me->http = http;
 613:   me->bufptr = me->buffer;
 614:   me->state = EOL_BEGIN;
 615:   return me;
 616: }
 617: 
 618: /* ------------------------------------------------------------------------- */
 619: 
 620: /*       Load Document from HTTP Server            HTLoadHTTP
1.55 frystyk 621: **       ==============================
 622: **
 623: **   Given a hypertext address, this routine loads a document.
 624: **
 625: ** On entry,
 626: **   request        This is the request structure
 627: ** On exit,
1.71 frystyk 628: **   returns     <0       Error has occured or interrupted
 629: **           HT_WOULD_BLOCK if operation would have blocked
1.58 frystyk 630: **           HT_LOADED    if return status 200 OK
 631: **           HT_NO_DATA   if return status 204 No Response
1.55 frystyk 632: */
 633: PUBLIC int HTLoadHTTP ARGS1 (HTRequest *, request)
 634: {
1.71 frystyk 635:   int status = HT_ERROR;
 636:   char *url;              /* Gets initialized on every entry */
1.55 frystyk 637:   http_info *http;            /* Specific protocol information */
 638: 
 639:   if (!request || !request->anchor) {
1.71 frystyk 640:     if (PROT_TRACE) fprintf(stderr, "HTLoadHTTP.. Bad argument\n");
 641:     return HT_ERROR;
1.55 frystyk 642:   }
 643:   url = HTAnchor_physical(request->anchor);
1.17 timbl 644:   
1.71 frystyk 645:   /* Only do the setup first time through. This is actually state HTTP_BEGIN
 646:    but it can't be in the state machine as we need the structure first */
 647:   if (!request->net_info) {
1.22 luotonen 648:    /*
1.71 frystyk 649:    ** Initiate a new http structure and bind to request structure
 650:    ** This is actually state HTTP_BEGIN, but it can't be in the state
 651:    ** machine as we need the structure first.
1.22 luotonen 652:    */
1.71 frystyk 653:    if (PROT_TRACE) fprintf(stderr, "HTTP........ Looking for `%s\'\n", url);
 654:    if ((http = (http_info *) calloc(1, sizeof(http_info))) == NULL)
 655:      outofmem(__FILE__, "HTLoadHTTP");
 656:    http->sockfd = -1;             /* Invalid socket number */
 657:    http->request = request;
 658:    http->state = HTTP_BEGIN;
 659:    request->net_info = (HTNetInfo *) http;
 660:    HTThread_new((HTNetInfo *) http);
 661:   } else
 662:    http = (http_info *) request->net_info;     /* Get existing copy */
 663: 
 664:   /* Now jump into the machine. We know the state from the previous run */
 665:   while (1) {
 666:    switch (http->state) {
 667:     case HTTP_BEGIN:
 668:      /*
 669:       ** Compose authorization information (this was moved here
 670:       ** from after the making of the connection so that the connection
 671:       ** wouldn't have to wait while prompting username and password
 672:       ** from the user).             -- AL 13.10.93
 673:       */
 674:      HTAA_composeAuth(request);
 675:      if (PROT_TRACE) {
 676:        if (request->authorization)
 677:          fprintf(stderr, "HTTP........ Sending Authorization: %s\n",
 678:              request->authorization);
 679:        else
 680:          fprintf(stderr,
 681:              "HTTP........ Not sending authorization (yet)\n");
 682:      }
 683:      http->state = HTTP_NEED_CONNECTION;
 684:      break;
 685:      
 686:     case HTTP_NEED_CONNECTION:    /* Now let's set up a connection */
 687:      status = HTDoConnect((HTNetInfo *) http, url, TCP_PORT,
 688:                 NULL, NO);
 689:      if (!status) {
 690:        if (PROT_TRACE)
 691:          fprintf(stderr, "HTTP........ Connected, socket %d\n",
 692:              http->sockfd);
 693:        http->isoc = HTInputSocket_new(http->sockfd);
 694:        http->state = HTTP_NEED_REQUEST;
 695:      } else if (status == HT_WOULD_BLOCK)
 696:        return status;
 697:      else
 698:        http->state = HTTP_ERROR;       /* Error or interrupt */
 699:      break;
 700: 
 701:     case HTTP_NEED_REQUEST:     /* Compose the request and send it */
 702:      if ((status = HTTPSendRequest(request, http, url)) < 0) {
 703:        if (status == HT_WOULD_BLOCK)
1.55 frystyk 704:          return status;
1.71 frystyk 705:        else
 706:          http->state = HTTP_ERROR;
1.55 frystyk 707:      } else {
1.71 frystyk 708:        http->state = HTTP_SENT_REQUEST;      
1.21 luotonen 709:      }
1.71 frystyk 710:      break;
1.21 luotonen 711: 
1.71 frystyk 712:     case HTTP_SENT_REQUEST:            /* Read the response */
 713:     case HTTP_NEED_BODY:
 714:      if (!http->target) {
 715:        if (HTImProxy)
 716:          http->target = request->output_stream;
 717:        else
 718:          http->target = HTTPStatus_new(request, http);
 719:      }
1.74 ! frystyk 720:      status = HTInputSocket_read(http->isoc, http->target);
 ! 721:      if (status == HT_WOULD_BLOCK)
1.71 frystyk 722:        return HT_WOULD_BLOCK;
1.74 ! frystyk 723:      else if (status == HT_INTERRUPTED)
 ! 724:        status = (*http->target->isa->abort)(http->target, NULL);
 ! 725:      else
 ! 726:        status = (*http->target->isa->_free)(http->target);
 ! 727:      if (status >= 0 && http->state == HTTP_NEED_BODY)
1.71 frystyk 728:        http->state = HTTP_GOT_DATA;
1.74 ! frystyk 729:      else
 ! 730:        http->state = HTTP_ERROR;
1.71 frystyk 731:      break;
 732: 
 733:      case HTTP_REDIRECTION:
 734:      if (request->redirect) {
 735:        HTAnchor *anchor;
 736:        if (status == 301) {
 737:          HTErrorAdd(request, ERR_INFO, NO, HTERR_MOVED,
 738:                (void *) request->redirect,
 739:                (int) strlen(request->redirect), "HTLoadHTTP");
 740:        } else if (status == 302) {
 741:          HTErrorAdd(request, ERR_INFO, NO, HTERR_FOUND,
 742:                (void *) request->redirect,
 743:                (int) strlen(request->redirect), "HTLoadHTTP");
1.55 frystyk 744:        }
1.71 frystyk 745:        anchor = HTAnchor_findAddress(request->redirect);
 746:        if (++request->redirections < HTMaxRedirections) {
 747:          HTTPCleanup(request);
 748:          return HTLoadAnchorRecursive((HTAnchor *) anchor, request);
 749:        } else {
 750:          HTErrorAdd(request, ERR_FATAL, NO, HTERR_MAX_REDIRECT,
1.58 frystyk 751:                NULL, 0, "HTLoadHTTP");
1.71 frystyk 752:          http->state = HTTP_ERROR;
1.58 frystyk 753:        }
1.71 frystyk 754:      } else {
 755:        HTErrorAdd(request, ERR_FATAL, NO, HTERR_BAD_REPLY,
 756:              NULL, 0, "HTLoadHTTP");
 757:        http->state = HTTP_ERROR;
 758:      }
 759:      break;
 760: 
 761:     case HTTP_AA:
1.74 ! frystyk 762:      HTTPCleanup(request);
1.71 frystyk 763:      if (HTTPAuthentication(request) == YES &&
 764:        HTAA_retryWithAuth(request) == YES) {
 765:        return HTLoadAnchor((HTAnchor *) request->anchor, request);
 766:      } else {
 767:        char *unescaped = NULL;
 768:        StrAllocCopy(unescaped, url);
 769:        HTUnEscape(unescaped);
 770:        HTErrorAdd(request, ERR_FATAL, NO, HTERR_UNAUTHORIZED,
 771:              (void *) unescaped,
 772:              (int) strlen(unescaped), "HTLoadHTTP");
 773:        free(unescaped);
 774:        http->state = HTTP_ERROR;
 775:      }
 776:      break;
 777: 
 778:     case HTTP_GOT_DATA:
1.74 ! frystyk 779:      HTTPCleanup(request);
1.71 frystyk 780:      return HT_LOADED;
 781:      break;
 782:      
 783:     case HTTP_NO_DATA:
 784:      HTTPCleanup(request);
 785:      return HT_NO_DATA;
 786:      break;
 787: 
 788:     case HTTP_ERROR:
 789:      HTTPCleanup(request);
 790:      return HT_ERROR;
 791:      break;
 792:    }
 793:   } /* End of while(1) */
 794: }  
 795: 
 796: /* Protocol descriptor */
 797: 
 798: #ifdef EVENT_LOOP
 799: GLOBALDEF PUBLIC HTProtocol HTTP = {
 800:   "http", SOC_NON_BLOCK, HTLoadHTTP, NULL, NULL
 801: };
 802: #else
 803: GLOBALDEF PUBLIC HTProtocol HTTP = {
 804:   "http", SOC_BLOCK, HTLoadHTTP, NULL, NULL
 805: };
1.55 frystyk 806: #endif
1.21 luotonen 807: 

Webmaster

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