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

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

Webmaster