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

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

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

Webmaster

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