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

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

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:    /* Put out referer field if any parent */
1.58 ! frystyk 236:    if (request->parentAnchor) {
1.56 frystyk 237:      char *this = HTAnchor_address((HTAnchor *) request->anchor);
1.58 ! frystyk 238:      char *parent = HTAnchor_address((HTAnchor *)request->parentAnchor);
1.56 frystyk 239:      char *relative = HTParse(parent, this,
 240:         PARSE_ACCESS|PARSE_HOST|PARSE_PATH|PARSE_PUNCTUATION);
 241:      if (relative && *relative) {
 242:        sprintf(line, "Referer: %s%c%c", parent, CR, LF);
 243:        HTChunkPuts(command, line);
 244:      }
 245:      free(this);
 246:      free(parent);
 247:      free(relative);
 248:    }
1.58 ! frystyk 249: 
1.55 frystyk 250:    /* Put out user-agent */
1.56 frystyk 251:    sprintf(line, "User-Agent: %s/%s libwww/%s%c%c",
 252:        HTAppName ? HTAppName : "unknown",
 253:        HTAppVersion ? HTAppVersion : "0.0",
 254:        HTLibraryVersion, CR, LF);
 255:    HTChunkPuts(command, line);
1.45 luotonen 256: 
1.55 frystyk 257:    /* Put out authorization */
 258:    if (request->authorization != NULL) {
 259:      HTChunkPuts(command, "Authorization: ");
 260:      HTChunkPuts(command, request->authorization);
 261:      HTChunkPutc(command, CR);
 262:      HTChunkPutc(command, LF);
1.37 luotonen 263:    }
1.55 frystyk 264:   }
 265:   HTChunkPutc(command, CR);           /* Blank line means "end" */
 266:   HTChunkPutc(command, LF);
 267:   HTChunkTerminate(command);
 268:   if (TRACE) fprintf(stderr, "HTTP Tx..... %s", command->data);
1.17 timbl 269:   
1.55 frystyk 270:   /* Translate into ASCII if necessary */
1.4 timbl 271: #ifdef NOT_ASCII
1.55 frystyk 272:   {
 273:    char * p;
 274:    for(p = command; *p; p++) {
 275:      *p = TOASCII(*p);
1.1 timbl 276:    }
1.55 frystyk 277:   }
1.3 timbl 278: #endif
1.17 timbl 279:   
1.55 frystyk 280:   /* Now, we are ready for sending the request */
 281:   if ((status = NETWRITE(http->socket, command->data, command->size)) < 0) {
 282:    if (TRACE) fprintf(stderr, "HTTP Tx..... Error sending command\n");
 283:    HTErrorSysAdd(request, ERR_FATAL, NO, "NETWRITE");
 284:    if (status != HT_INTERRUPTED) {
 285:      char *unescaped = NULL;
 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);
 292:    }
 293:   }
 294:   HTChunkFree(command);
 295:   return status;
 296: }
 297: 
 298: 
 299: /*                               HTTPGetBody
 300: **
 301: **   Put up a streamstack and read the body from the socket.
 302: **   In the special case of user asking for source and the message
 303: **   being in MIME, we force the MIME decoding to occur, as it is really
 304: **   HTTP decoding. If the user really wants the HTTP headers, he
 305: **   can ask for them as www/mime.
 306: **
 307: **   Returns < 0 on error, else HT_LOADED
 308: */
 309: PRIVATE int HTTPGetBody ARGS5(HTRequest *, request, http_info *, http,
 310:               HTInputSocket *, isoc, HTFormat, format_in,
 311:               BOOL, use_cache)
 312: {
 313:   int status = -1;
 314:   HTStream *target = NULL;              /* Unconverted data */
 315:   if (format_in == WWW_MIME && request->output_format == WWW_SOURCE) {
 316:    target = HTMIMEConvert(request, NULL, format_in,
 317:                request->output_format,
 318:                request->output_stream);
 319:   } else
 320:    target = HTStreamStack(format_in, request, NO);
 321:   if (target) {
 322:    
 323:    /* @@ Bug: The decision of whether or not to cache should also
 324:      be made contingent on a IP address match or non match. */
 325:    
 326:    if (HTCacheDir && use_cache) {
 327:      target = HTTee(target,
 328:              HTCacheWriter(request, NULL, format_in,
 329:                     request->output_format,
 330:                     request->output_stream));
1.17 timbl 331:    }
1.55 frystyk 332:    
 333:    /* Push the data down the stream remembering the end of the
 334:      first buffer we just read */
 335:    if (format_in == WWW_HTML)
 336:      target = HTNetToText(target);/* Pipe through CR stripper */
 337:    
 338:    PUTBLOCK(isoc->input_pointer,
 339:         isoc->input_limit-isoc->input_pointer);
 340:    HTCopy(http->socket, target);        /* USE RETURN AS STATUS */
 341:    FREE_TARGET;
 342:    status = HT_LOADED;
 343:   }
 344:   return status;
 345: }
 346: 
 347: 
1.56 frystyk 348: /*                               HTTPRedirect
 349: **
 350: **   Reads the response from a 3xx server status code. Only the first line
 351: **   is read. The format expected is
 352: **
 353: **   Location: <url> String CrLf
 354: **
 355: **   The comment string is ignored!
 356: **
 357: **   NOTE: THIS IS NOT IN CORRESPONDANCE WITH THE SPECS!!!
 358: **
 359: **   Returns new anchor on success else NULL
 360: */
 361: PRIVATE HTAnchor *HTTPRedirect ARGS3(HTRequest *, request,
 362:                   HTInputSocket *, isoc, int, code)
 363: {
 364:   BOOL found = NO;
 365:   HTAnchor *anchor = NULL;                 /* New anchor */
 366:   char *line;
 367:   if (TRACE)
 368:    fprintf(stderr, "Redirection. Looking for URL's\n");
 369:   while ((line = HTInputSocket_getUnfoldedLine(isoc)) != NULL) {
 370:    char *strptr = line;
 371:    if (*strptr) {
 372:      while (*strptr && *strptr == ' ')     /* Skip leading spaces */
 373:        strptr++;
 374:      if (!strncasecomp(strptr, "location:", 9)) {
 375:        char *url = strchr(strptr, ' ');
 376:        char *comment;
 377:        while (*url && *url == ' ')      /* Skip leading spaces */
 378:          url++;
 379:        if ((comment = strchr(url, ' ')) != NULL)
 380:          *comment = '0円';          /* Skip any comments */
 381:        if (code == 301)
1.57 frystyk 382:          HTErrorAdd(request, ERR_INFO, NO, HTERR_MOVED,
1.56 frystyk 383:                (void *) url, (int) strlen(url),
 384:                "HTTPRedirect");
 385:        else if (code == 302)
1.57 frystyk 386:          HTErrorAdd(request, ERR_INFO, NO, HTERR_FOUND,
1.56 frystyk 387:                (void *) url, (int) strlen(url),
 388:                "HTTPRedirect");
 389:        else {
 390:          if (TRACE)
 391:            fprintf(stderr,
 392:                "Redirection. Weird, should never happen\n");
 393:        }
 394: 
 395:        /* Now use the new anchor instead of the old one */
 396:        anchor = HTAnchor_findAddress(url);
 397:        found = YES;
 398:        FREE(line);
 399:        break;
 400:      }
 401:    }
 402:    free(line);
 403:   }
 404: 
 405:   if (!found) {
 406:    int length = (int) strlen(line);
 407:    HTErrorAdd(request, ERR_FATAL, NO, HTERR_BAD_REPLY,
 408:          (void *) line, length < 50 ? length : 50, "HTTPRedirect");
 409:   }
 410:   return anchor;
 411: }
 412: 
 413: 
1.55 frystyk 414: /*       Load Document from HTTP Server         HTLoadHTTP()
 415: **       ==============================
 416: **
 417: **   Given a hypertext address, this routine loads a document.
 418: **
 419: ** On entry,
 420: **   request        This is the request structure
 421: ** On exit,
 422: **   returns     <0       Error has occured
1.58 ! frystyk 423: **           HT_LOADED    if return status 200 OK
 ! 424: **           HT_NO_DATA   if return status 204 No Response
1.55 frystyk 425: */
 426: PUBLIC int HTLoadHTTP ARGS1 (HTRequest *, request)
 427: {
 428:   char *url;
 429:   int status = -1;                     /* tcp return */
 430:   http_info *http;            /* Specific protocol information */
 431: 
 432:   if (!request || !request->anchor) {
 433:     if (TRACE) fprintf(stderr, "HTLoadHTTP.. Bad argument\n");
 434:     return -1;
 435:   }
 436:   url = HTAnchor_physical(request->anchor);
 437:   HTSimplify(url);
 438:   if (TRACE) fprintf(stderr, "HTTP........ Looking for `%s\'\n", url);
 439: 
 440:   /* Initiate a new http structure */
 441:   if ((http = (http_info *) calloc(1, sizeof(http_info))) == NULL)
 442:     outofmem(__FILE__, "HTLoadHTTP");
 443:   http->socket = -1;
1.17 timbl 444:   
1.55 frystyk 445: /*
 446: ** Compose authorization information (this was moved here
 447: ** from after the making of the connection so that the connection
 448: ** wouldn't have to wait while prompting username and password
 449: ** from the user).               -- AL 13.10.93
 450: */
 451:   HTAA_composeAuth(request);
 452:   if (TRACE) {
 453:    if (request->authorization)
 454:      fprintf(stderr, "HTTP........ Sending Authorization: %s\n",
 455:          request->authorization);
 456:    else
 457:      fprintf(stderr, "HTTP........ Not sending authorization (yet)\n");
 458:   }
 459: 
 460:   /* Now let's set up a connection */
 461:   if ((status = HTDoConnect(request, url, TCP_PORT,
 462:               &http->socket, NULL)) < 0) {
 463:     if (TRACE)
 464:       fprintf(stderr, "HTTP........ Connection not established!\n");
 465:    if (status != HT_INTERRUPTED) {
 466:      char *unescaped = NULL;
 467:      StrAllocCopy(unescaped, url);
 468:      HTUnEscape(unescaped);
 469:      HTErrorAdd(request, ERR_FATAL, NO, HTERR_INTERNAL,
 470:            (void *) unescaped, (int) strlen(unescaped),
 471:            "HTLoadHTTP");
 472:      free(unescaped);
 473:    }
 474:    HTTPCleanup(request, http);
 475:    return status;
 476:   }
 477:   if (TRACE) fprintf(stderr, "HTTP........ Connected, socket %d\n",
 478:            http->socket);
 479: 
 480:   /* Compose the request and send it over the net */
 481:   if ((status = HTTPSendRequest(request, http, url)) < 0) {
 482:    HTTPCleanup(request, http);
 483:    return status;
 484:   }  
1.2 timbl 485: 
1.17 timbl 486: /*   Read the response
 487: **   -----------------
1.11 timbl 488: **
 489: **   HTTP0 servers must return ASCII style text, though it can in
 490: **   principle be just text without any markup at all.
 491: **   Full HTTP servers must return a response
 492: **   line and RFC822 style header. The response must therefore in
 493: **   either case have a CRLF somewhere soon.
 494: **
 495: **   This is the theory. In practice, there are (1993) unfortunately
 496: **   many binary documents just served up with HTTP0.9. This
 497: **   means we have to preserve the binary buffer (on the assumption that
 498: **   conversion from ASCII may lose information) in case it turns
 499: **   out that we want the binary original.
1.2 timbl 500: */
1.53 luotonen 501: 
 502:   CTRACE(stderr, "Waiting..... for response\n");
 503: 
1.37 luotonen 504:   if (HTImProxy) {
1.24 luotonen 505: 
1.22 luotonen 506:    /*
 507:    ** Server as a gateway -- send body of the message
 508:    ** received from client (if any).
 509:    */
 510:    if (request->isoc && request->content_length > 0) {
 511:      int remain = request->content_length;
 512:      int i = remain;
 513:      char * buf;
 514: 
 515:      while (remain > 0 &&
 516:          (buf = HTInputSocket_getBlock(request->isoc, &i))) {
1.55 frystyk 517:        int status = NETWRITE(http->socket, buf, i);
1.22 luotonen 518:        if (status < 0) {
1.27 luotonen 519:          CTRACE(stderr, "HTTPAccess.. Unable to forward body\n");
1.55 frystyk 520:          HTErrorSysAdd(request, ERR_FATAL, NO, "NETWRITE");
 521:          HTTPCleanup(request, http);
 522:          return status;
1.22 luotonen 523:        }
 524:        remain -= i;
 525:        i = remain;
 526:      }
 527:    }
1.23 luotonen 528: 
 529:    /*
1.22 luotonen 530:    ** Load results directly to client
 531:    */
1.55 frystyk 532:    HTCopy(http->socket, request->output_stream);
1.25 luotonen 533:    (*request->output_stream->isa->free)(request->output_stream);
1.55 frystyk 534:    HTTPCleanup(request, http);
1.22 luotonen 535:    return HT_LOADED;
1.55 frystyk 536:   } else {                        /* read response */
1.21 luotonen 537: 
1.17 timbl 538:    HTFormat format_in;       /* Format arriving in the message */
1.55 frystyk 539:    HTInputSocket *isoc = HTInputSocket_new(http->socket);
 540:    char *status_line = HTInputSocket_getStatusLine(isoc);
1.2 timbl 541: 
1.11 timbl 542: /* Kludge to trap binary responses from illegal HTTP0.9 servers.
 543: ** First time we have enough, look at the stub in ASCII
 544: ** and get out of here if it doesn't look right.
 545: **
 546: ** We also check for characters above 128 in the first few bytes, and
 547: ** if we find them we forget the html default.
 548: **
 549: ** Bugs: A HTTP0.9 server returning a document starting "HTTP/"
 550: **   will be taken as a HTTP 1.0 server. Failure.
 551: **   An HTTP 0.9 server returning a binary document with
 552: **   characters < 128 will be read as ASCII.
 553: */
1.36 frystyk 554:    /* If HTTP 0 response, then DO NOT CACHE (Henrik 14/02-94) */
 555:    if (!status_line) {   
1.21 luotonen 556:      if (HTInputSocket_seemsBinary(isoc)) {
 557:        format_in = HTAtom_for("www/unknown");
1.55 frystyk 558:      } else {
1.21 luotonen 559:        format_in = WWW_HTML;
 560:      }
1.55 frystyk 561:      status = HTTPGetBody(request, http, isoc, format_in, NO);
 562:    } else {
1.21 luotonen 563:      /*
 564:      ** We now have a terminated server status line, and we have
 565:      ** checked that it is most probably a legal one. Parse it.
 566:      */
 567:      char server_version[VERSION_LENGTH+1];
 568:      int server_status;
 569: 
 570:      if (TRACE)
1.55 frystyk 571:        fprintf(stderr, "HTTP Rx..... `%.70s\'\n", status_line);
 572:      {
 573:        char formatstr[20];
 574:        sprintf(formatstr, "%%%ds%%d", VERSION_LENGTH);
 575:        if (sscanf(status_line, formatstr, server_version,
 576:              &server_status) < 2) {
 577:          int length = (int) strlen(status_line);
 578:          HTErrorAdd(request, ERR_FATAL, NO, HTERR_BAD_REPLY,
 579:                (void *) status_line, length < 50 ? length : 50,
 580:                "HTLoadHTTP");
 581:          HTInputSocket_free(isoc);    
 582:          free(http);
 583:          free(status_line);
 584:          return -1;                /* Bad response */
 585:        }
 586:        *(server_version+VERSION_LENGTH) = '0円';
 587:      }
1.21 luotonen 588:      format_in = HTAtom_for("www/mime");
1.7 timbl 589:   
1.55 frystyk 590:      /* Big switch for all response codes */
 591:      switch (server_status/100) {
1.2 timbl 592: 
1.55 frystyk 593:       case 2:      /* Good: Got MIME object */
1.58 ! frystyk 594:        switch (server_status) {
 ! 595:         case 204:                  /* No response */
 ! 596:          HTErrorAdd(request, ERR_INFO, NO, HTERR_NO_RESPONSE,
 ! 597:                NULL, 0, "HTLoadHTTP");
 ! 598:          status = HT_NO_DATA;
 ! 599:          break;               /* Don't get any body */
 ! 600:         case 203:                    /* Partial */
 ! 601:          HTErrorAdd(request, ERR_INFO, NO, HTERR_PARTIAL,
 ! 602:                NULL, 0, "HTLoadHTTP");
 ! 603:          /* Drop through to 200 as we still have to get the body */
 ! 604:         case 200:
 ! 605:          status = HTTPGetBody(request, http, isoc, format_in, YES);
 ! 606:          break;
 ! 607:         default:
 ! 608:          {
 ! 609:            int length = (int) strlen(status_line);
 ! 610:            HTErrorAdd(request, ERR_FATAL, NO, HTERR_BAD_REPLY,
 ! 611:                  (void *) status_line, length < 50 ?
 ! 612:                  length : 50, "HTLoadHTTP");
 ! 613:          }
 ! 614:          status = -1;
 ! 615:          break;
 ! 616:        }
1.21 luotonen 617:        break;
1.58 ! frystyk 618: 
1.21 luotonen 619:       case 3:      /* Various forms of redirection */
1.55 frystyk 620:        switch (server_status) {
 621:         case 301:                     /* Moved */
 622:         case 302:                     /* Found */
1.56 frystyk 623:          {
 624:            HTParentAnchor *anchor;
 625:            if ((anchor = (HTParentAnchor *)
 626:               HTTPRedirect(request, isoc,
 627:                     server_status)) != NULL) {
 628:              free(status_line);
 629:              HTInputSocket_free(isoc);
 630:              HTTPCleanup(request, http);
1.58 ! frystyk 631: 
 ! 632:              /* Now do a recursive call but keep error stack */
 ! 633:              if (HTLoadAnchorRecursive((HTAnchor *) anchor,
 ! 634:                           request) == YES)
1.56 frystyk 635:                return HT_LOADED;
 636:              else
 637:                return -1;
 638:            }
 639:          }
 640:          break;
1.55 frystyk 641:         case 303:                    /* Method */
1.56 frystyk 642:          HTAlert("This client doesn't support automatic redirection of type `Method'");
 643:          status = -1;
1.55 frystyk 644:          break;
 645:         case 304:              /* Not modified Since */
 646:          {
 647:            char *unescaped = NULL;
 648:            StrAllocCopy(unescaped, url);
 649:            HTUnEscape(unescaped);
1.57 frystyk 650:            HTErrorAdd(request, ERR_INFO, NO,
1.55 frystyk 651:                  HTERR_NOT_MODIFIED, (void *) unescaped,
 652:                  (int) strlen(unescaped), "HTLoadHTTP");
 653:            free(unescaped);
 654:          }
 655:          status = HT_LOADED;
 656:          break;
 657: 
 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.17 timbl 669:          
1.21 luotonen 670:       case 4:      /* Access Authorization problem */
 671:        switch (server_status) {
 672:         case 401:
 673:          parse_401_headers(request, isoc);
 674: 
 675:          if (TRACE) fprintf(stderr, "%s %d %s\n",
1.55 frystyk 676:                    "HTTP: close socket", http->socket,
1.21 luotonen 677:                    "to retry with Access Authorization");
1.24 luotonen 678:          if (HTAA_retryWithAuth(request, HTLoadHTTP)) {
1.21 luotonen 679:            status = HT_LOADED;/* @@ THIS ONLY WORKS ON LINEMODE */
1.55 frystyk 680:            break;
1.21 luotonen 681:          }
 682:          /* else falltrough */
 683:         default:
1.14 luotonen 684:          {
1.55 frystyk 685:            char *unescaped = NULL;
 686:            StrAllocCopy(unescaped, url);
 687:            HTUnEscape(unescaped);
 688:            HTErrorAdd(request, ERR_FATAL, NO, HTERR_UNAUTHORIZED,
 689:                  (void *) unescaped,
 690:                  (int) strlen(unescaped), "HTLoadHTTP");
 691:            free(unescaped);
 692: #ifdef OLD_CODE
 693:            char *p1 = HTParse(url, "", PARSE_HOST);
1.21 luotonen 694:            char * message;
 695: 
 696:            if (!(message = (char*)malloc(strlen(status_line) +
 697:                           strlen(p1) + 100)))
 698:              outofmem(__FILE__, "HTTP 4xx status");
1.14 luotonen 699:            sprintf(message,
1.21 luotonen 700:                "HTTP server at %s replies:\n%s\n\n%s\n",
 701:                p1, status_line,
 702:                ((server_status == 401) 
 703:                 ? "Access Authorization package giving up.\n"
 704:                 : ""));
1.22 luotonen 705:            status = HTLoadError(request, server_status, message);
1.14 luotonen 706:            free(message);
 707:            free(p1);
1.55 frystyk 708: #endif /* OLD_CODE */
1.14 luotonen 709:          }
1.55 frystyk 710:          status = -1;
 711:          break;
 712:        }
1.21 luotonen 713:        break;
 714: 
 715:       case 5:      /* I think you goofed */
 716:        {
1.55 frystyk 717:          char *unescaped = NULL;
 718:          StrAllocCopy(unescaped, url);
 719:          HTUnEscape(unescaped);
 720:          HTErrorAdd(request, ERR_FATAL, NO, HTERR_INTERNAL,
 721:                (void *) unescaped, (int) strlen(unescaped),
 722:                "HTLoadHTTP");
 723:          free(unescaped);
 724: #ifdef OLD_CODE
 725:          char *p1 = HTParse(url, "", PARSE_HOST);
1.21 luotonen 726:          char * message = (char*)malloc(strlen(status_line) + 
 727:                          strlen(p1) + 100);
 728:          if (!message) outofmem(__FILE__, "HTTP 5xx status");
 729:          sprintf(message,
 730:              "HTTP server at %s replies:\n%s", p1, status_line);
1.22 luotonen 731:          status = HTLoadError(request, server_status, message);
1.21 luotonen 732:          free(message);
 733:          free(p1);
1.55 frystyk 734: #endif
1.21 luotonen 735:        }
1.55 frystyk 736:        status = -1;
1.21 luotonen 737:        break;
1.55 frystyk 738: 
 739:       default:                     /* bad number */
 740:        {
 741:          int length = (int) strlen(status_line);
 742:          HTErrorAdd(request, ERR_FATAL, NO, HTERR_BAD_REPLY,
 743:                (void *) status_line, length < 50 ? length : 50,
 744:                "HTLoadHTTP");
 745:        }
 746:        status = -1;
1.21 luotonen 747:        break;
1.55 frystyk 748:      }
 749:      FREE(status_line);          /* Leak fix Henrik 18/02-94 */
1.17 timbl 750:    }
1.48 timbl 751: 
1.55 frystyk 752:    /* Close the socket and free memory */
 753:    HTInputSocket_free(isoc);      
 754:    HTTPCleanup(request, http);
 755:    return status;         /* Good return */  
 756:   }
 757: }
1.1 timbl 758: 
 759: /*   Protocol descriptor
 760: */
 761: 
1.17 timbl 762: GLOBALDEF PUBLIC HTProtocol HTTP = { "http", HTLoadHTTP, 0, 0 };
1.55 frystyk 763: 
 764: 
1.21 luotonen 765: 

Webmaster

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