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

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

1.44 frystyk 1: /*   HyperText73 Tranfer Protocol  - Client implementation     HTTP.c
1.1 timbl 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.55 frystyk 11: **
1.1 timbl 12: */
 13: 
1.2 timbl 14: #define HTTP_VERSION  "HTTP/1.0"
1.55 frystyk 15: #define HTTP2                /* Version is greater than 0.9 */
 16: #define VERSION_LENGTH         20  /* Number of chars in protocol version */
1.2 timbl 17: 
1.55 frystyk 18: /* Uses: */
1.1 timbl 19: #include "HTParse.h"
 20: #include "HTUtils.h"
1.68 frystyk 21: 
 22: /* System dependent stuff */
1.1 timbl 23: #include "tcp.h"
1.68 frystyk 24: 
 25: /* Library Includes */
1.1 timbl 26: #include "HTTCP.h"
 27: #include "HTFormat.h"
1.2 timbl 28: #include "HTAlert.h"
 29: #include "HTMIME.h"
1.5 timbl 30: #include "HTML.h"       /* SCW */
 31: #include "HTInit.h"      /* SCW */
1.21 luotonen 32: #include "HTAccess.h"     /* HTRequest */
1.14 luotonen 33: #include "HTAABrow.h"     /* Access Authorization */
1.20 timbl 34: #include "HTTee.h"       /* Tee off a cache stream */
 35: #include "HTFWriter.h"     /* Write to cache file */
1.54 luotonen 36: #include "HTError.h"
1.55 frystyk 37: #include "HTChunk.h"
 38: #include "HTTP.h"                       /* Implements */
 39: 
 40: /* Macros and other defines */
 41: #define PUTBLOCK(b, l) (*target->isa->put_block)(target, b, l)
 42: #define PUTS(s)        (*target->isa->put_string)(target, s)
1.67 duns 43: #define FREE_TARGET  (*target->isa->_free)(target)
1.1 timbl 44: 
1.2 timbl 45: struct _HTStream {
 46:    HTStreamClass * isa;      /* all we need to know */
 47: };
 48: 
1.55 frystyk 49: /* Globals */
1.59 frystyk 50: extern char * HTAppName;         /* Application name: please supply */
 51: extern char * HTAppVersion;      /* Application version: please supply */
1.64 frystyk 52: PUBLIC int HTMaxRedirections = 10;      /* Max number of redirections */
 53: PUBLIC BOOL HTEnableFrom = NO;            /* Enable From header? */
1.6 timbl 54: 
1.50 luotonen 55: #ifdef OLD_CODE
1.37 luotonen 56: PUBLIC long HTProxyBytes = 0; /* Number of bytes transferred thru proxy */
1.50 luotonen 57: #endif
 58: 
1.37 luotonen 59: extern BOOL using_proxy;    /* are we using a proxy gateway? */
 60: PUBLIC char * HTProxyHeaders = NULL;  /* Headers to pass as-is */
1.23 luotonen 61: 
1.59 frystyk 62: /* Type definitions and global variables etc. local to this module */
 63: /* This is the local definition of HTRequest->net_info */
 64: typedef enum _HTTPState {
 65:   HTTP_ERROR  = -2,
 66:   HTTP_FAILURE = -1,
 67:   HTTP_IDLE  = 0,
 68:   HTTP_BEGIN,
 69:   HTTP_INTERRUPTED,
 70:   HTTP_CONNECTED,
 71:   HTTP_SEND_REQUEST,
1.65 frystyk 72:   HTTP_GOT_RESPONSE
1.59 frystyk 73: } HTTPState;
1.55 frystyk 74: 
 75: typedef struct _http_info {
1.68 frystyk 76:   int            sockfd;      /* Socket number for communication */
 77:   HTInputSocket *  isoc;                /* Input buffer */
 78:   int        addressCount; /* No. of attempts if multi-homed host */
 79:   BOOL        CRLFdotCRLF;      /* Transmission end like this */
 80:   HTRequest *        request;            /* Request structure */
 81: 
 82:   HTTPState     state;          /* State of the connection */
1.55 frystyk 83: } http_info;
 84: 
 85: /* ------------------------------------------------------------------------- */
 86: 
1.21 luotonen 87: PRIVATE void parse_401_headers ARGS2(HTRequest *,   req,
 88:                   HTInputSocket *,  isoc)
 89: {
 90:   HTAAScheme scheme;
 91:   char *line;
 92:   int num_schemes = 0;
 93:   HTList *valid_schemes = HTList_new();
 94:   HTAssocList **scheme_specifics = NULL;
1.69 frystyk 95:   char *tmplate = NULL;
1.21 luotonen 96: 
 97:   /* Read server reply header lines */
 98: 
 99:   if (TRACE)
 100:    fprintf(stderr, "Server 401 reply header lines:\n");
 101: 
 102:   while (NULL != (line = HTInputSocket_getUnfoldedLine(isoc)) &&
 103:      *line != 0) {
 104: 
 105:    if (TRACE) fprintf(stderr, "%s\n", line);
 106: 
 107:    if (strchr(line, ':')) {    /* Valid header line */
 108: 
 109:      char *p = line;
 110:      char *fieldname = HTNextField(&p);
 111:      char *arg1 = HTNextField(&p);
 112:      char *args = p;
 113:      
 114:      if (0==strcasecomp(fieldname, "WWW-Authenticate:")) {
 115:        if (HTAA_UNKNOWN != (scheme = HTAAScheme_enum(arg1))) {
 116:          HTList_addObject(valid_schemes, (void*)scheme);
 117:          if (!scheme_specifics) {
 118:            int i;
 119:            scheme_specifics = (HTAssocList**)
 120:              malloc(HTAA_MAX_SCHEMES * sizeof(HTAssocList*));
 121:            if (!scheme_specifics)
 122:              outofmem(__FILE__, "parse_401_headers");
 123:            for (i=0; i < HTAA_MAX_SCHEMES; i++)
 124:              scheme_specifics[i] = NULL;
 125:          }
 126:          scheme_specifics[scheme] = HTAA_parseArgList(args);
 127:          num_schemes++;
 128:        }
 129:        else if (TRACE) {
 130:          fprintf(stderr, "Unknown scheme `%s' %s\n",
 131:              (arg1 ? arg1 : "(null)"),
 132:              "in WWW-Authenticate: field");
 133:        }
 134:      }
 135: 
 136:      else if (0==strcasecomp(fieldname, "WWW-Protection-Template:")) {
 137:        if (TRACE)
 138:          fprintf(stderr, "Protection template set to `%s'\n", arg1);
1.69 frystyk 139:        StrAllocCopy(tmplate, arg1);
1.21 luotonen 140:      }
 141: 
 142:    } /* if a valid header line */
 143:    else if (TRACE) {
 144:      fprintf(stderr, "Invalid header line `%s' ignored\n", line);
 145:    } /* else invalid header line */
1.44 frystyk 146:    free(line);
1.21 luotonen 147:   } /* while header lines remain */
1.44 frystyk 148:   FREE(line);
1.21 luotonen 149:   req->valid_schemes = valid_schemes;
 150:   req->scheme_specifics = scheme_specifics;
1.69 frystyk 151:   req->prot_template = tmplate;
1.21 luotonen 152: }
 153: 
 154: 
1.55 frystyk 155: /*                               HTTPCleanup
1.1 timbl 156: **
1.55 frystyk 157: **   This function closes the connection and frees memory.
1.1 timbl 158: **
1.55 frystyk 159: **   Returns 0 on OK, else -1
1.1 timbl 160: */
1.59 frystyk 161: PRIVATE int HTTPCleanup ARGS1(http_info *, http)
1.1 timbl 162: {
1.55 frystyk 163:   int status = 0;
1.59 frystyk 164:   if (!http) {
1.55 frystyk 165:    if (TRACE) fprintf(stderr, "HTTPCleanup. Bad argument!\n");
 166:    status = -1;
 167:   } else {
1.59 frystyk 168:    if (http->sockfd >= 0) {
1.55 frystyk 169:      if (TRACE) fprintf(stderr, "HTTP........ Closing socket %d\n",
1.59 frystyk 170:                http->sockfd);
 171:      if ((status = NETCLOSE(http->sockfd)) < 0)
 172:        HTErrorSysAdd(http->request, ERR_FATAL, NO, "NETCLOSE");
 173:    }
1.55 frystyk 174:   } 
 175:   free(http);
 176:   return status;
 177: }
1.36 frystyk 178: 
1.23 luotonen 179: 
1.55 frystyk 180: /*                               HTTPSendRequest
 181: **
 182: **   This function composes and sends a request to the connected server
 183: **   specified.
 184: **
 185: **   Returns 0 on OK, else -1 but does NOT close the connection
1.1 timbl 186: */
1.55 frystyk 187: PRIVATE int HTTPSendRequest ARGS3(HTRequest *, request,
 188:                 http_info *, http, char *, url)
 189: {
 190:   int status = 0;
 191:   BOOL extensions = YES;            /* Assume good HTTP server */
 192:   HTChunk *command = HTChunkCreate(2048);      /* The whole command */
 193:   if (request->method != METHOD_INVALID) {
 194:    HTChunkPuts(command, HTMethod_name(request->method));
 195:    HTChunkPutc(command, ' ');
 196:   }
 197:   else
 198:    HTChunkPuts(command, "GET ");
1.1 timbl 199: 
1.55 frystyk 200:   /* if we are using a proxy gateway don't copy in the first slash
 201:   ** of say: /gopher://a;lkdjfl;ajdf;lkj/;aldk/adflj
 202:   ** so that just gohper://.... is sent. */
1.1 timbl 203:   {
1.55 frystyk 204:    char *p1 = HTParse(url, "", PARSE_PATH|PARSE_PUNCTUATION);
 205:    if (using_proxy)
 206:      HTChunkPuts(command, p1+1);
1.21 luotonen 207:    else
1.55 frystyk 208:      HTChunkPuts(command, p1);
 209:    free(p1);
1.15 luotonen 210:   }
1.1 timbl 211: 
1.2 timbl 212: #ifdef HTTP2
1.55 frystyk 213:   if (extensions) {
 214:    HTChunkPutc(command, ' ');
 215:    HTChunkPuts(command, HTTP_VERSION);
 216:   }
1.2 timbl 217: #endif
1.55 frystyk 218:   HTChunkPutc(command, CR);            /* CR LF, as in rfc 977 */
 219:   HTChunkPutc(command, LF);
1.17 timbl 220:   
1.55 frystyk 221:   if (extensions && HTImProxy && HTProxyHeaders) {
 222:    HTChunkPuts(command, HTProxyHeaders);
 223:   } else if (extensions) {
1.56 frystyk 224:    char line[256];  /*@@@@ */
1.55 frystyk 225: 
 226:    /* If no conversion list, then put it up, but leave initialization
 227:      to the client */
 228:    if (!HTConversions)
 229:      HTConversions = HTList_new();
1.21 luotonen 230: 
1.55 frystyk 231:    /* Run through both lists and generate `accept' lines */
 232:    {
1.17 timbl 233:      int i;
1.21 luotonen 234:      HTList *conversions[2];
 235:      conversions[0] = HTConversions;
 236:      conversions[1] = request->conversions;
1.34 frystyk 237:      
1.21 luotonen 238:      for (i=0; i<2; i++) {
 239:        HTList *cur = conversions[i];
 240:        HTPresentation *pres;
1.55 frystyk 241:        while ((pres = (HTPresentation *) HTList_nextObject(cur))) {
 242:          if (pres->rep_out == WWW_PRESENT) {
1.21 luotonen 243:            if (pres->quality != 1.0) {
1.35 frystyk 244:              sprintf(line, "Accept: %s; q=%.3f%c%c",
1.21 luotonen 245:                  HTAtom_name(pres->rep),
 246:                  pres->quality, CR, LF);
 247:            } else {
 248:              sprintf(line, "Accept: %s%c%c",
 249:                  HTAtom_name(pres->rep), CR, LF);
 250:            }
1.55 frystyk 251:            HTChunkPuts(command, line);
1.17 timbl 252:          }
 253:        }
1.2 timbl 254:      }
1.55 frystyk 255:    }
1.22 luotonen 256: 
1.56 frystyk 257:    /* Put out referer field if any parent */
1.58 frystyk 258:    if (request->parentAnchor) {
1.69 frystyk 259:      char *me = HTAnchor_address((HTAnchor *) request->anchor);
1.58 frystyk 260:      char *parent = HTAnchor_address((HTAnchor *)request->parentAnchor);
1.69 frystyk 261:      char *relative = HTParse(parent, me,
1.56 frystyk 262:         PARSE_ACCESS|PARSE_HOST|PARSE_PATH|PARSE_PUNCTUATION);
 263:      if (relative && *relative) {
 264:        sprintf(line, "Referer: %s%c%c", parent, CR, LF);
 265:        HTChunkPuts(command, line);
 266:      }
1.69 frystyk 267:      free(me);
1.56 frystyk 268:      free(parent);
 269:      free(relative);
 270:    }
1.58 frystyk 271: 
1.64 frystyk 272:    /* Put out from field if enabled by client */
 273:    if (HTEnableFrom) {
1.63 frystyk 274:      CONST char *mailaddress = HTGetMailAddress();
 275:      if (mailaddress != NULL) {
 276:        sprintf(line, "From: %s%c%c", mailaddress, CR, LF);
 277:        HTChunkPuts(command, line);
 278:      }
 279:    }
 280:   
1.55 frystyk 281:    /* Put out user-agent */
1.56 frystyk 282:    sprintf(line, "User-Agent: %s/%s libwww/%s%c%c",
 283:        HTAppName ? HTAppName : "unknown",
 284:        HTAppVersion ? HTAppVersion : "0.0",
 285:        HTLibraryVersion, CR, LF);
 286:    HTChunkPuts(command, line);
1.45 luotonen 287: 
1.55 frystyk 288:    /* Put out authorization */
 289:    if (request->authorization != NULL) {
 290:      HTChunkPuts(command, "Authorization: ");
 291:      HTChunkPuts(command, request->authorization);
 292:      HTChunkPutc(command, CR);
 293:      HTChunkPutc(command, LF);
1.37 luotonen 294:    }
1.55 frystyk 295:   }
 296:   HTChunkPutc(command, CR);           /* Blank line means "end" */
 297:   HTChunkPutc(command, LF);
 298:   HTChunkTerminate(command);
 299:   if (TRACE) fprintf(stderr, "HTTP Tx..... %s", command->data);
1.17 timbl 300:   
1.55 frystyk 301:   /* Translate into ASCII if necessary */
1.4 timbl 302: #ifdef NOT_ASCII
1.55 frystyk 303:   {
 304:    char * p;
1.59 frystyk 305:    for(p = command->data; *p; p++) {
1.55 frystyk 306:      *p = TOASCII(*p);
1.1 timbl 307:    }
1.55 frystyk 308:   }
1.3 timbl 309: #endif
1.17 timbl 310:   
1.55 frystyk 311:   /* Now, we are ready for sending the request */
1.64 frystyk 312:   if ((status = NETWRITE(http->sockfd, command->data, command->size-1))<0) {
1.55 frystyk 313:    if (TRACE) fprintf(stderr, "HTTP Tx..... Error sending command\n");
 314:    HTErrorSysAdd(request, ERR_FATAL, NO, "NETWRITE");
 315:    if (status != HT_INTERRUPTED) {
 316:      char *unescaped = NULL;
 317:      StrAllocCopy(unescaped, url);
 318:      HTUnEscape(unescaped);
 319:      HTErrorAdd(request, ERR_FATAL, NO, HTERR_INTERNAL,
 320:            (void *) unescaped, (int) strlen(unescaped),
 321:            "HTTPSendRequest");
 322:      free(unescaped);
 323:    }
 324:   }
 325:   HTChunkFree(command);
 326:   return status;
 327: }
 328: 
 329: 
 330: /*                               HTTPGetBody
 331: **
 332: **   Put up a streamstack and read the body from the socket.
 333: **   In the special case of user asking for source and the message
 334: **   being in MIME, we force the MIME decoding to occur, as it is really
 335: **   HTTP decoding. If the user really wants the HTTP headers, he
 336: **   can ask for them as www/mime.
 337: **
 338: **   Returns < 0 on error, else HT_LOADED
 339: */
1.59 frystyk 340: PRIVATE int HTTPGetBody ARGS4(HTRequest *, request, http_info *, http,
 341:               HTFormat, format_in, BOOL, use_cache)
1.55 frystyk 342: {
 343:   int status = -1;
 344:   HTStream *target = NULL;              /* Unconverted data */
1.70 ! howcome 345:   HTStream *s;                    /* HWL */
 ! 346: 
1.55 frystyk 347:   if (format_in == WWW_MIME && request->output_format == WWW_SOURCE) {
 348:    target = HTMIMEConvert(request, NULL, format_in,
 349:                request->output_format,
 350:                request->output_stream);
 351:   } else
 352:    target = HTStreamStack(format_in, request, NO);
 353:   if (target) {
 354:    
 355:    /* @@ Bug: The decision of whether or not to cache should also
 356:      be made contingent on a IP address match or non match. */
 357:    
 358:    if (HTCacheDir && use_cache) {
1.70 ! howcome 359: /*
 ! 360:       target = HTTee(target,
 ! 361:              HTCacheWriter(request, NULL, format_in,
 ! 362:                     request->output_format,
 ! 363:                     request->output_stream));
 ! 364: */
 ! 365:      /* HWL added check for s */
 ! 366:      s = HTCacheWriter(request, NULL, format_in,
 ! 367:             request->output_format,
 ! 368:             request->output_stream);
 ! 369:      if (s != NULL) {
 ! 370:        target = HTTee(target, s);
 ! 371:      }
 ! 372: 
1.17 timbl 373:    }
1.55 frystyk 374:    
 375:    /* Push the data down the stream remembering the end of the
 376:      first buffer we just read */
 377:    if (format_in == WWW_HTML)
 378:      target = HTNetToText(target);/* Pipe through CR stripper */
 379:    
1.59 frystyk 380:    PUTBLOCK(http->isoc->input_pointer,
 381:         http->isoc->input_limit - http->isoc->input_pointer);
 382:    HTCopy(http->sockfd, target);        /* USE RETURN AS STATUS */
1.55 frystyk 383:    FREE_TARGET;
 384:    status = HT_LOADED;
 385:   }
 386:   return status;
 387: }
 388: 
 389: 
1.56 frystyk 390: /*                               HTTPRedirect
 391: **
 392: **   Reads the response from a 3xx server status code. Only the first line
 393: **   is read. The format expected is
 394: **
1.68 frystyk 395: **   Location: <url> String CrLf   OR   URI: <url> String CrLf 
1.56 frystyk 396: **
 397: **   The comment string is ignored!
 398: **
 399: **   NOTE: THIS IS NOT IN CORRESPONDANCE WITH THE SPECS!!!
 400: **
 401: **   Returns new anchor on success else NULL
 402: */
 403: PRIVATE HTAnchor *HTTPRedirect ARGS3(HTRequest *, request,
1.59 frystyk 404:                   http_info *, http, int, code)
1.56 frystyk 405: {
 406:   BOOL found = NO;
 407:   HTAnchor *anchor = NULL;                 /* New anchor */
 408:   char *line;
 409:   if (TRACE)
 410:    fprintf(stderr, "Redirection. Looking for URL's\n");
1.59 frystyk 411:   while ((line = HTInputSocket_getUnfoldedLine(http->isoc)) != NULL) {
1.56 frystyk 412:    char *strptr = line;
 413:    if (*strptr) {
 414:      while (*strptr && *strptr == ' ')     /* Skip leading spaces */
 415:        strptr++;
1.68 frystyk 416:      if (!strncasecomp(strptr, "location:", 9) ||
 417:        !strncasecomp(strptr, "uri:", 4)) {
1.56 frystyk 418:        char *url = strchr(strptr, ' ');
 419:        char *comment;
 420:        while (*url && *url == ' ')      /* Skip leading spaces */
 421:          url++;
 422:        if ((comment = strchr(url, ' ')) != NULL)
 423:          *comment = '0円';          /* Skip any comments */
 424:        if (code == 301)
1.57 frystyk 425:          HTErrorAdd(request, ERR_INFO, NO, HTERR_MOVED,
1.56 frystyk 426:                (void *) url, (int) strlen(url),
 427:                "HTTPRedirect");
 428:        else if (code == 302)
1.57 frystyk 429:          HTErrorAdd(request, ERR_INFO, NO, HTERR_FOUND,
1.56 frystyk 430:                (void *) url, (int) strlen(url),
 431:                "HTTPRedirect");
 432:        else {
 433:          if (TRACE)
 434:            fprintf(stderr,
 435:                "Redirection. Weird, should never happen\n");
 436:        }
 437: 
 438:        /* Now use the new anchor instead of the old one */
 439:        anchor = HTAnchor_findAddress(url);
 440:        found = YES;
 441:        FREE(line);
 442:        break;
 443:      }
 444:    }
 445:    free(line);
 446:   }
 447: 
 448:   if (!found) {
 449:    int length = (int) strlen(line);
 450:    HTErrorAdd(request, ERR_FATAL, NO, HTERR_BAD_REPLY,
 451:          (void *) line, length < 50 ? length : 50, "HTTPRedirect");
 452:   }
 453:   return anchor;
 454: }
 455: 
 456: 
1.55 frystyk 457: /*       Load Document from HTTP Server         HTLoadHTTP()
 458: **       ==============================
 459: **
 460: **   Given a hypertext address, this routine loads a document.
 461: **
 462: ** On entry,
 463: **   request        This is the request structure
 464: ** On exit,
 465: **   returns     <0       Error has occured
1.58 frystyk 466: **           HT_LOADED    if return status 200 OK
 467: **           HT_NO_DATA   if return status 204 No Response
1.55 frystyk 468: */
 469: PUBLIC int HTLoadHTTP ARGS1 (HTRequest *, request)
 470: {
 471:   char *url;
1.59 frystyk 472:   int    status = -1;                  /* The current status */
1.55 frystyk 473:   http_info *http;            /* Specific protocol information */
 474: 
 475:   if (!request || !request->anchor) {
 476:     if (TRACE) fprintf(stderr, "HTLoadHTTP.. Bad argument\n");
 477:     return -1;
 478:   }
 479:   url = HTAnchor_physical(request->anchor);
 480:   if (TRACE) fprintf(stderr, "HTTP........ Looking for `%s\'\n", url);
 481: 
1.59 frystyk 482:   /* Initiate a new http structure and bind to request structure */
 483:   /* this is actually state HTTP_BEGIN, but it can't be in the state */
 484:   /* machine as we need the structure first. */
1.55 frystyk 485:   if ((http = (http_info *) calloc(1, sizeof(http_info))) == NULL)
1.59 frystyk 486:    outofmem(__FILE__, "HTLoadHTTP");
 487:   http->sockfd = -1;               /* Invalid socket number */
 488:   http->request = request;
 489:   http->state = HTTP_IDLE;
 490:   request->net_info = (HTNetInfo *) http;
1.17 timbl 491:   
1.59 frystyk 492:   /*
 493:   ** Compose authorization information (this was moved here
 494:   ** from after the making of the connection so that the connection
 495:   ** wouldn't have to wait while prompting username and password
 496:   ** from the user).                -- AL 13.10.93
 497:   */
1.55 frystyk 498:   HTAA_composeAuth(request);
 499:   if (TRACE) {
 500:    if (request->authorization)
 501:      fprintf(stderr, "HTTP........ Sending Authorization: %s\n",
 502:          request->authorization);
 503:    else
 504:      fprintf(stderr, "HTTP........ Not sending authorization (yet)\n");
 505:   }
 506: 
1.64 frystyk 507:   /* Now let's set up a connection and input buffer */
1.68 frystyk 508:   if ((status = HTDoConnect((HTNetInfo *) http, url, TCP_PORT,
 509:               NULL, NO)) < 0) {
1.59 frystyk 510:    if (TRACE)
 511:      fprintf(stderr, "HTTP........ Connection not established\n");
1.55 frystyk 512:    if (status != HT_INTERRUPTED) {
 513:      char *unescaped = NULL;
 514:      StrAllocCopy(unescaped, url);
 515:      HTUnEscape(unescaped);
 516:      HTErrorAdd(request, ERR_FATAL, NO, HTERR_INTERNAL,
 517:            (void *) unescaped, (int) strlen(unescaped),
 518:            "HTLoadHTTP");
 519:      free(unescaped);
 520:    }
1.59 frystyk 521:    HTTPCleanup(http);
1.55 frystyk 522:    return status;
 523:   }
 524:   if (TRACE) fprintf(stderr, "HTTP........ Connected, socket %d\n",
1.59 frystyk 525:            http->sockfd);
1.55 frystyk 526: 
1.59 frystyk 527:   /* Compose the request and send it */
1.55 frystyk 528:   if ((status = HTTPSendRequest(request, http, url)) < 0) {
1.59 frystyk 529:    HTTPCleanup(http);
1.55 frystyk 530:    return status;
 531:   }  
1.2 timbl 532: 
1.17 timbl 533: /*   Read the response
 534: **   -----------------
1.11 timbl 535: **
 536: **   HTTP0 servers must return ASCII style text, though it can in
 537: **   principle be just text without any markup at all.
 538: **   Full HTTP servers must return a response
 539: **   line and RFC822 style header. The response must therefore in
 540: **   either case have a CRLF somewhere soon.
 541: **
 542: **   This is the theory. In practice, there are (1993) unfortunately
 543: **   many binary documents just served up with HTTP0.9. This
 544: **   means we have to preserve the binary buffer (on the assumption that
 545: **   conversion from ASCII may lose information) in case it turns
 546: **   out that we want the binary original.
1.2 timbl 547: */
1.53 luotonen 548: 
 549:   CTRACE(stderr, "Waiting..... for response\n");
 550: 
1.37 luotonen 551:   if (HTImProxy) {
1.24 luotonen 552: 
1.22 luotonen 553:    /*
 554:    ** Server as a gateway -- send body of the message
 555:    ** received from client (if any).
 556:    */
 557:    if (request->isoc && request->content_length > 0) {
 558:      int remain = request->content_length;
 559:      int i = remain;
 560:      char * buf;
 561: 
 562:      while (remain > 0 &&
 563:          (buf = HTInputSocket_getBlock(request->isoc, &i))) {
1.59 frystyk 564:        int status = NETWRITE(http->sockfd, buf, i);
1.22 luotonen 565:        if (status < 0) {
1.27 luotonen 566:          CTRACE(stderr, "HTTPAccess.. Unable to forward body\n");
1.55 frystyk 567:          HTErrorSysAdd(request, ERR_FATAL, NO, "NETWRITE");
1.59 frystyk 568:          HTTPCleanup(http);
1.55 frystyk 569:          return status;
1.22 luotonen 570:        }
 571:        remain -= i;
 572:        i = remain;
 573:      }
 574:    }
1.23 luotonen 575: 
 576:    /*
1.22 luotonen 577:    ** Load results directly to client
 578:    */
1.59 frystyk 579:    HTCopy(http->sockfd, request->output_stream);
1.67 duns 580:    (*request->output_stream->isa->_free)(request->output_stream);
1.59 frystyk 581:    HTTPCleanup(http);
1.22 luotonen 582:    return HT_LOADED;
1.55 frystyk 583:   } else {                        /* read response */
1.21 luotonen 584: 
1.17 timbl 585:    HTFormat format_in;       /* Format arriving in the message */
1.59 frystyk 586:    char *status_line = NULL;
1.68 frystyk 587:    http->isoc = HTInputSocket_new(http->sockfd);
1.59 frystyk 588:    status_line = HTInputSocket_getStatusLine(http->isoc);
1.2 timbl 589: 
1.11 timbl 590: /* Kludge to trap binary responses from illegal HTTP0.9 servers.
 591: ** First time we have enough, look at the stub in ASCII
 592: ** and get out of here if it doesn't look right.
 593: **
 594: ** We also check for characters above 128 in the first few bytes, and
 595: ** if we find them we forget the html default.
 596: **
 597: ** Bugs: A HTTP0.9 server returning a document starting "HTTP/"
 598: **   will be taken as a HTTP 1.0 server. Failure.
 599: **   An HTTP 0.9 server returning a binary document with
 600: **   characters < 128 will be read as ASCII.
 601: */
1.36 frystyk 602:    /* If HTTP 0 response, then DO NOT CACHE (Henrik 14/02-94) */
1.68 frystyk 603:    if (!status_line) {
 604:      if (PROT_TRACE)
 605:        fprintf(stderr, 
 606:            "HTTP........ This seems like a HTTP 0.9 server\n");
1.59 frystyk 607:      if (HTInputSocket_seemsBinary(http->isoc)) {
1.21 luotonen 608:        format_in = HTAtom_for("www/unknown");
1.55 frystyk 609:      } else {
1.21 luotonen 610:        format_in = WWW_HTML;
 611:      }
1.59 frystyk 612:      status = HTTPGetBody(request, http, format_in, NO);
1.55 frystyk 613:    } else {
1.21 luotonen 614:      /*
 615:      ** We now have a terminated server status line, and we have
 616:      ** checked that it is most probably a legal one. Parse it.
 617:      */
 618:      char server_version[VERSION_LENGTH+1];
 619:      int server_status;
 620: 
 621:      if (TRACE)
1.55 frystyk 622:        fprintf(stderr, "HTTP Rx..... `%.70s\'\n", status_line);
 623:      {
 624:        char formatstr[20];
 625:        sprintf(formatstr, "%%%ds%%d", VERSION_LENGTH);
 626:        if (sscanf(status_line, formatstr, server_version,
 627:              &server_status) < 2) {
 628:          int length = (int) strlen(status_line);
 629:          HTErrorAdd(request, ERR_FATAL, NO, HTERR_BAD_REPLY,
 630:                (void *) status_line, length < 50 ? length : 50,
 631:                "HTLoadHTTP");
1.59 frystyk 632:          HTInputSocket_free(http->isoc);
1.55 frystyk 633:          free(http);
 634:          free(status_line);
 635:          return -1;                /* Bad response */
 636:        }
 637:        *(server_version+VERSION_LENGTH) = '0円';
 638:      }
1.21 luotonen 639:      format_in = HTAtom_for("www/mime");
1.7 timbl 640:   
1.55 frystyk 641:      /* Big switch for all response codes */
 642:      switch (server_status/100) {
1.2 timbl 643: 
1.55 frystyk 644:       case 2:      /* Good: Got MIME object */
1.58 frystyk 645:        switch (server_status) {
 646:         case 204:                  /* No response */
 647:          HTErrorAdd(request, ERR_INFO, NO, HTERR_NO_RESPONSE,
 648:                NULL, 0, "HTLoadHTTP");
 649:          status = HT_NO_DATA;
 650:          break;               /* Don't get any body */
 651:         case 203:                    /* Partial */
 652:          HTErrorAdd(request, ERR_INFO, NO, HTERR_PARTIAL,
 653:                NULL, 0, "HTLoadHTTP");
 654:          /* Drop through to 200 as we still have to get the body */
 655:         case 200:
1.59 frystyk 656:          status = HTTPGetBody(request, http, format_in, YES);
1.58 frystyk 657:          break;
 658:         default:
 659:          {
 660:            int length = (int) strlen(status_line);
 661:            HTErrorAdd(request, ERR_FATAL, NO, HTERR_BAD_REPLY,
 662:                  (void *) status_line, length < 50 ?
 663:                  length : 50, "HTLoadHTTP");
 664:          }
 665:          status = -1;
 666:          break;
 667:        }
1.21 luotonen 668:        break;
1.58 frystyk 669: 
1.21 luotonen 670:       case 3:      /* Various forms of redirection */
1.55 frystyk 671:        switch (server_status) {
 672:         case 301:                     /* Moved */
 673:         case 302:                     /* Found */
1.56 frystyk 674:          {
 675:            HTParentAnchor *anchor;
 676:            if ((anchor = (HTParentAnchor *)
1.59 frystyk 677:               HTTPRedirect(request, http,
1.56 frystyk 678:                     server_status)) != NULL) {
 679:              free(status_line);
1.59 frystyk 680:              HTInputSocket_free(http->isoc);
 681:              HTTPCleanup(http);
1.68 frystyk 682:              request->redirections++;
1.58 frystyk 683: 
1.59 frystyk 684:              /* If we have not reached the roof for redirects
 685:                then call HTLoadAnchor recursively but keep
 686:                the error_stack so that the user knows what
 687:                is going on */
1.68 frystyk 688:              if (request->redirections < HTMaxRedirections) {
1.59 frystyk 689:                if (HTLoadAnchorRecursive((HTAnchor *) anchor,
 690:                             request) == YES)
 691:                  return HT_LOADED;
 692:                else
 693:                  return -1;
 694:              } else {              
 695:                HTErrorAdd(request, ERR_FATAL, NO, 
 696:                      HTERR_MAX_REDIRECT, NULL, 0,
 697:                      "HTTLoadHTTP");
1.56 frystyk 698:                return -1;
1.59 frystyk 699:              }
1.56 frystyk 700:            }
 701:          }
 702:          break;
1.55 frystyk 703:         case 303:                    /* Method */
1.56 frystyk 704:          HTAlert("This client doesn't support automatic redirection of type `Method'");
 705:          status = -1;
1.55 frystyk 706:          break;
 707:         case 304:              /* Not modified Since */
 708:          {
 709:            char *unescaped = NULL;
 710:            StrAllocCopy(unescaped, url);
 711:            HTUnEscape(unescaped);
1.57 frystyk 712:            HTErrorAdd(request, ERR_INFO, NO,
1.55 frystyk 713:                  HTERR_NOT_MODIFIED, (void *) unescaped,
 714:                  (int) strlen(unescaped), "HTLoadHTTP");
 715:            free(unescaped);
 716:          }
 717:          status = HT_LOADED;
 718:          break;
 719: 
 720:         default:
 721:          {
 722:            int length = (int) strlen(status_line);
 723:            HTErrorAdd(request, ERR_FATAL, NO, HTERR_BAD_REPLY,
 724:                  (void *) status_line, length < 50 ?
 725:                  length : 50, "HTLoadHTTP");
 726:          }
 727:          status = -1;
 728:          break;
 729:        }
1.21 luotonen 730:        break;
1.17 timbl 731:          
1.21 luotonen 732:       case 4:      /* Access Authorization problem */
 733:        switch (server_status) {
1.68 frystyk 734:         case 400:
 735:          {
 736:            char *unescaped = NULL;
 737:            StrAllocCopy(unescaped, url);
 738:            HTUnEscape(unescaped);
 739:            HTErrorAdd(request, ERR_FATAL, NO,
 740:                  HTERR_BAD_REQUEST, (void *) unescaped,
 741:                  (int) strlen(unescaped), "HTLoadHTTP");
 742:            free(unescaped);
 743:          }
 744:          status = -1;
 745:          break;
1.21 luotonen 746:         case 401:
1.59 frystyk 747:          parse_401_headers(request, http->isoc);
1.68 frystyk 748:          if (TRACE) fprintf(stderr, "HTTP........ Closing socket %d to retry with Access Autorization\n", http->sockfd);
 749:          if ((status = NETCLOSE(http->sockfd)) < 0) {
 750:            HTErrorSysAdd(http->request, ERR_FATAL, NO,"NETCLOSE");
 751:            break;
 752:          }
 753:          http->sockfd = -1;
1.24 luotonen 754:          if (HTAA_retryWithAuth(request, HTLoadHTTP)) {
1.21 luotonen 755:            status = HT_LOADED;/* @@ THIS ONLY WORKS ON LINEMODE */
1.55 frystyk 756:            break;
1.68 frystyk 757:          } else {
 758:            char *unescaped = NULL;
 759:            StrAllocCopy(unescaped, url);
 760:            HTUnEscape(unescaped);
 761:            HTErrorAdd(request, ERR_FATAL, NO, HTERR_UNAUTHORIZED,
 762:                  (void *) unescaped,
 763:                  (int) strlen(unescaped), "HTLoadHTTP");
 764:            free(unescaped);
 765:            status = -1;
1.21 luotonen 766:          }
1.68 frystyk 767:          break;
 768:         case 402:
 769:          {
 770:            char *unescaped = NULL;
 771:            StrAllocCopy(unescaped, url);
 772:            HTUnEscape(unescaped);
 773:            HTErrorAdd(request, ERR_FATAL, NO,
 774:                  HTERR_PAYMENT_REQUIRED, (void *) unescaped,
 775:                  (int) strlen(unescaped), "HTLoadHTTP");
 776:            free(unescaped);
 777:          }
 778:          status = -1;
 779:          break;
 780:         case 403:
 781:          {
 782:            char *unescaped = NULL;
 783:            StrAllocCopy(unescaped, url);
 784:            HTUnEscape(unescaped);
 785:            HTErrorAdd(request, ERR_FATAL, NO,
 786:                  HTERR_FORBIDDEN, (void *) unescaped,
 787:                  (int) strlen(unescaped), "HTLoadHTTP");
 788:            free(unescaped);
 789:          }
 790:          status = -1;
 791:          break;
 792:         case 404:
 793:          {
 794:            char *unescaped = NULL;
 795:            StrAllocCopy(unescaped, url);
 796:            HTUnEscape(unescaped);
 797:            HTErrorAdd(request, ERR_FATAL, NO,
 798:                  HTERR_NOT_FOUND, (void *) unescaped,
 799:                  (int) strlen(unescaped), "HTLoadHTTP");
 800:            free(unescaped);
 801:          }
 802:          status = -1;
 803:          break;
1.21 luotonen 804:         default:
1.14 luotonen 805:          {
1.55 frystyk 806:            char *unescaped = NULL;
 807:            StrAllocCopy(unescaped, url);
 808:            HTUnEscape(unescaped);
1.68 frystyk 809:            HTErrorAdd(request, ERR_FATAL, NO, HTERR_BAD_REPLY,
1.55 frystyk 810:                  (void *) unescaped,
 811:                  (int) strlen(unescaped), "HTLoadHTTP");
 812:            free(unescaped);
 813: #ifdef OLD_CODE
 814:            char *p1 = HTParse(url, "", PARSE_HOST);
1.21 luotonen 815:            char * message;
 816: 
 817:            if (!(message = (char*)malloc(strlen(status_line) +
 818:                           strlen(p1) + 100)))
 819:              outofmem(__FILE__, "HTTP 4xx status");
1.14 luotonen 820:            sprintf(message,
1.21 luotonen 821:                "HTTP server at %s replies:\n%s\n\n%s\n",
 822:                p1, status_line,
 823:                ((server_status == 401) 
 824:                 ? "Access Authorization package giving up.\n"
 825:                 : ""));
1.22 luotonen 826:            status = HTLoadError(request, server_status, message);
1.14 luotonen 827:            free(message);
 828:            free(p1);
1.55 frystyk 829: #endif /* OLD_CODE */
1.14 luotonen 830:          }
1.55 frystyk 831:          status = -1;
 832:          break;
 833:        }
1.21 luotonen 834:        break;
 835: 
 836:       case 5:      /* I think you goofed */
 837:        {
1.55 frystyk 838:          char *unescaped = NULL;
 839:          StrAllocCopy(unescaped, url);
 840:          HTUnEscape(unescaped);
 841:          HTErrorAdd(request, ERR_FATAL, NO, HTERR_INTERNAL,
 842:                (void *) unescaped, (int) strlen(unescaped),
 843:                "HTLoadHTTP");
 844:          free(unescaped);
 845: #ifdef OLD_CODE
 846:          char *p1 = HTParse(url, "", PARSE_HOST);
1.21 luotonen 847:          char * message = (char*)malloc(strlen(status_line) + 
 848:                          strlen(p1) + 100);
 849:          if (!message) outofmem(__FILE__, "HTTP 5xx status");
 850:          sprintf(message,
 851:              "HTTP server at %s replies:\n%s", p1, status_line);
1.22 luotonen 852:          status = HTLoadError(request, server_status, message);
1.21 luotonen 853:          free(message);
 854:          free(p1);
1.55 frystyk 855: #endif
1.21 luotonen 856:        }
1.55 frystyk 857:        status = -1;
1.21 luotonen 858:        break;
1.55 frystyk 859: 
 860:       default:                     /* bad number */
 861:        {
 862:          int length = (int) strlen(status_line);
 863:          HTErrorAdd(request, ERR_FATAL, NO, HTERR_BAD_REPLY,
 864:                (void *) status_line, length < 50 ? length : 50,
 865:                "HTLoadHTTP");
 866:        }
 867:        status = -1;
1.21 luotonen 868:        break;
1.55 frystyk 869:      }
 870:      FREE(status_line);          /* Leak fix Henrik 18/02-94 */
1.17 timbl 871:    }
1.48 timbl 872: 
1.55 frystyk 873:    /* Close the socket and free memory */
1.59 frystyk 874:    HTInputSocket_free(http->isoc);
 875:    HTTPCleanup(http);
1.55 frystyk 876:    return status;         /* Good return */  
 877:   }
 878: }
1.1 timbl 879: 
 880: /*   Protocol descriptor
 881: */
 882: 
1.17 timbl 883: GLOBALDEF PUBLIC HTProtocol HTTP = { "http", HTLoadHTTP, 0, 0 };
1.55 frystyk 884: 
 885: 
1.21 luotonen 886: 

Webmaster

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