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

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

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

Webmaster

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