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

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

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

Webmaster

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