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

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

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

Webmaster

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