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

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

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

Webmaster

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