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

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

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.71 ! frystyk 45: extern BOOL using_proxy;    /      * are we using a proxy gateway? */
 ! 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 {
 ! 744:        HTErrorAdd(request, ERR_FATAL, NO, HTERR_BAD_REPLY,
 ! 745:              NULL, 0, "HTLoadHTTP");
 ! 746:        http->state = HTTP_ERROR;
 ! 747:      }
 ! 748:      break;
 ! 749: 
 ! 750:     case HTTP_AA:
 ! 751:      if (HTTPAuthentication(request) == YES &&
 ! 752:        HTAA_retryWithAuth(request) == YES) {
 ! 753:        HTTPCleanup(request);
 ! 754:        return HTLoadAnchor((HTAnchor *) request->anchor, request);
 ! 755:      } else {
 ! 756:        char *unescaped = NULL;
 ! 757:        StrAllocCopy(unescaped, url);
 ! 758:        HTUnEscape(unescaped);
 ! 759:        HTErrorAdd(request, ERR_FATAL, NO, HTERR_UNAUTHORIZED,
 ! 760:              (void *) unescaped,
 ! 761:              (int) strlen(unescaped), "HTLoadHTTP");
 ! 762:        free(unescaped);
 ! 763:        http->state = HTTP_ERROR;
 ! 764:      }
 ! 765:      break;
 ! 766: 
 ! 767:     case HTTP_GOT_DATA:
 ! 768:      return HT_LOADED;
 ! 769:      break;
 ! 770:      
 ! 771:     case HTTP_NO_DATA:
 ! 772:      HTTPCleanup(request);
 ! 773:      return HT_NO_DATA;
 ! 774:      break;
 ! 775: 
 ! 776:     case HTTP_ERROR:
 ! 777:      HTTPCleanup(request);
 ! 778:      return HT_ERROR;
 ! 779:      break;
 ! 780:    }
 ! 781:   } /* End of while(1) */
 ! 782: }  
 ! 783: 
 ! 784: /* Protocol descriptor */
 ! 785: 
 ! 786: #ifdef EVENT_LOOP
 ! 787: GLOBALDEF PUBLIC HTProtocol HTTP = {
 ! 788:   "http", SOC_NON_BLOCK, HTLoadHTTP, NULL, NULL
 ! 789: };
 ! 790: #else
 ! 791: GLOBALDEF PUBLIC HTProtocol HTTP = {
 ! 792:   "http", SOC_BLOCK, HTLoadHTTP, NULL, NULL
 ! 793: };
1.55 frystyk 794: #endif
1.21 luotonen 795: 

Webmaster

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