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

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

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

Webmaster

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