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

1.44      frystyk     1: /*     HyperText73 Tranfer Protocol    - Client implementation         HTTP.c
1.1       timbl       2: **     ==========================
1.2       timbl       3: **
                      4: ** Bugs:
                      5: **     Not implemented:
                      6: **             Forward
                      7: **             Redirection
                      8: **             Error handling
1.1       timbl       9: */
                     10: 
                     11: /*     Module parameters:
                     12: **     -----------------
                     13: **
                     14: **  These may be undefined and redefined by syspec.h
                     15: */
1.2       timbl      16: 
                     17: /* Implements:
                     18: */
                     19: #include "HTTP.h"
                     20: 
                     21: #define HTTP_VERSION   "HTTP/1.0"
                     22: #define HTTP2                          /* Version is greater than 0.9 */
                     23: 
                     24: #define INIT_LINE_SIZE         1024    /* Start with line buffer this big */
                     25: #define LINE_EXTEND_THRESH     256     /* Minimum read size */
                     26: #define VERSION_LENGTH                 20      /* for returned protocol version */
                     27: 
                     28: /* Uses:
                     29: */
1.1       timbl      30: #include "HTParse.h"
                     31: #include "HTUtils.h"
                     32: #include "tcp.h"
                     33: #include "HTTCP.h"
                     34: #include "HTFormat.h"
1.2       timbl      35: #include <ctype.h>
                     36: #include "HTAlert.h"
                     37: #include "HTMIME.h"
1.5       timbl      38: #include "HTML.h"              /* SCW */
                     39: #include "HTInit.h"            /* SCW */
1.21      luotonen   40: #include "HTAccess.h"          /* HTRequest */
1.14      luotonen   41: #include "HTAABrow.h"          /* Access Authorization */
1.20      timbl      42: #include "HTTee.h"             /* Tee off a cache stream */
                     43: #include "HTFWriter.h"         /* Write to cache file */
1.54    ! luotonen   44: #include "HTError.h"
1.1       timbl      45: 
1.2       timbl      46: struct _HTStream {
                     47:        HTStreamClass * isa;            /* all we need to know */
                     48: };
                     49: 
1.6       timbl      50: extern char * HTAppName;       /* Application name: please supply */
                     51: extern char * HTAppVersion;    /* Application version: please supply */
                     52: 
1.50      luotonen   53: #ifdef OLD_CODE
1.37      luotonen   54: PUBLIC long HTProxyBytes = 0;  /* Number of bytes transferred thru proxy */
1.50      luotonen   55: #endif
                     56: 
1.37      luotonen   57: extern BOOL using_proxy;       /* are we using a proxy gateway? */
                     58: PUBLIC char * HTProxyHeaders = NULL;   /* Headers to pass as-is */
1.23      luotonen   59: 
1.21      luotonen   60: PRIVATE void parse_401_headers ARGS2(HTRequest *,      req,
                     61:                                     HTInputSocket *,   isoc)
                     62: {
                     63:     HTAAScheme scheme;
                     64:     char *line;
                     65:     int num_schemes = 0;
                     66:     HTList *valid_schemes = HTList_new();
                     67:     HTAssocList **scheme_specifics = NULL;
                     68:     char *template = NULL;
                     69: 
                     70:     /* Read server reply header lines */
                     71: 
                     72:     if (TRACE)
                     73:        fprintf(stderr, "Server 401 reply header lines:\n");
                     74: 
                     75:     while (NULL != (line = HTInputSocket_getUnfoldedLine(isoc)) &&
                     76:           *line != 0) {
                     77: 
                     78:        if (TRACE) fprintf(stderr, "%s\n", line);
                     79: 
                     80:        if (strchr(line, ':')) {        /* Valid header line */
                     81: 
                     82:            char *p = line;
                     83:            char *fieldname = HTNextField(&p);
                     84:            char *arg1 = HTNextField(&p);
                     85:            char *args = p;
                     86:            
                     87:            if (0==strcasecomp(fieldname, "WWW-Authenticate:")) {
                     88:                if (HTAA_UNKNOWN != (scheme = HTAAScheme_enum(arg1))) {
                     89:                    HTList_addObject(valid_schemes, (void*)scheme);
                     90:                    if (!scheme_specifics) {
                     91:                        int i;
                     92:                        scheme_specifics = (HTAssocList**)
                     93:                            malloc(HTAA_MAX_SCHEMES * sizeof(HTAssocList*));
                     94:                        if (!scheme_specifics)
                     95:                            outofmem(__FILE__, "parse_401_headers");
                     96:                        for (i=0; i < HTAA_MAX_SCHEMES; i++)
                     97:                            scheme_specifics[i] = NULL;
                     98:                    }
                     99:                    scheme_specifics[scheme] = HTAA_parseArgList(args);
                    100:                    num_schemes++;
                    101:                }
                    102:                else if (TRACE) {
                    103:                    fprintf(stderr, "Unknown scheme `%s' %s\n",
                    104:                            (arg1 ? arg1 : "(null)"),
                    105:                            "in WWW-Authenticate: field");
                    106:                }
                    107:            }
                    108: 
                    109:            else if (0==strcasecomp(fieldname, "WWW-Protection-Template:")) {
                    110:                if (TRACE)
                    111:                    fprintf(stderr, "Protection template set to `%s'\n", arg1);
                    112:                StrAllocCopy(template, arg1);
                    113:            }
                    114: 
                    115:        } /* if a valid header line */
                    116:        else if (TRACE) {
                    117:            fprintf(stderr, "Invalid header line `%s' ignored\n", line);
                    118:        } /* else invalid header line */
1.44      frystyk   119:        free(line);
1.21      luotonen  120:     } /* while header lines remain */
1.44      frystyk   121:     FREE(line);
1.21      luotonen  122:     req->valid_schemes = valid_schemes;
                    123:     req->scheme_specifics = scheme_specifics;
                    124:     req->prot_template = template;
                    125: }
                    126: 
                    127: 
                    128: 
1.1       timbl     129: /*             Load Document from HTTP Server                  HTLoadHTTP()
                    130: **             ==============================
                    131: **
                    132: **     Given a hypertext address, this routine loads a document.
                    133: **
                    134: **
                    135: ** On entry,
                    136: **     arg     is the hypertext reference of the article to be loaded.
                    137: **
                    138: ** On exit,
                    139: **     returns >=0     If no error, a good socket number
                    140: **             <0      Error.
                    141: **
                    142: **     The socket must be closed by the caller after the document has been
                    143: **     read.
                    144: **
                    145: */
1.19      timbl     146: PUBLIC int HTLoadHTTP ARGS1 (HTRequest *, request)
1.1       timbl     147: {
1.22      luotonen  148:     CONST char * arg = NULL;
1.1       timbl     149:     int s;                             /* Socket number for returned data */
                    150:     int status;                                /* tcp return */
1.10      timbl     151:     char crlf[3];                      /* A CR LF equivalent string */
1.3       timbl     152:     HTStream * target = NULL;          /* Unconverted data */
1.46      frystyk   153:     BOOL cache_http = YES;        /* Enable caching of HTTP-retrieved files */
                    154: 
1.2       timbl     155:     CONST char* gate = 0;              /* disable this feature */
1.1       timbl     156:     SockA soc_address;                 /* Binary network address */
                    157:     SockA * sin = &soc_address;
1.40      frystyk   158:     BOOL extensions = YES;             /* Assume good HTTP server */
1.36      frystyk   159: 
1.50      luotonen  160: #ifdef OLD_CODE
1.37      luotonen  161:     if (HTImProxy) HTProxyBytes = 0;
1.50      luotonen  162: #endif
1.23      luotonen  163: 
1.37      luotonen  164:     arg = HTAnchor_physical(request->anchor);
1.22      luotonen  165: 
1.1       timbl     166:     if (!arg) return -3;               /* Bad if no name sepcified     */
                    167:     if (!*arg) return -2;              /* Bad if name had zero length  */
                    168: 
                    169: /*  Set up defaults:
                    170: */
                    171: #ifdef DECNET
1.2       timbl     172:     sin->sdn_family = AF_DECnet;           /* Family = DECnet, host order */
                    173:     sin->sdn_objnum = DNP_OBJ;          /* Default: http object number */
1.1       timbl     174: #else  /* Internet */
1.2       timbl     175:     sin->sin_family = AF_INET;     /* Family = internet, host order */
                    176:     sin->sin_port = htons(TCP_PORT);    /* Default: http port    */
1.1       timbl     177: #endif
                    178: 
1.10      timbl     179:     sprintf(crlf, "%c%c", CR, LF);     /* To be corect on Mac, VM, etc */
                    180:     
1.1       timbl     181:     if (TRACE) {
                    182:         if (gate) fprintf(stderr,
                    183:                "HTTPAccess: Using gateway %s for %s\n", gate, arg);
                    184:         else fprintf(stderr, "HTTPAccess: Direct access for %s\n", arg);
                    185:     }
                    186:     
                    187: /* Get node name and optional port number:
                    188: */
                    189:     {
                    190:        char *p1 = HTParse(gate ? gate : arg, "", PARSE_HOST);
                    191:        int status = HTParseInet(sin, p1);  /* TBL 920622 */
1.49      luotonen  192:        if (status) {
1.54    ! luotonen  193: #if 0
1.49      luotonen  194:            HTAddError2(request,"No such host:",p1);
1.54    ! luotonen  195: #endif
        !           196:            HTErrorAdd(request, ERR_FATAL, NO, HTERR_NO_REMOTE_HOST,
        !           197:                       (void*)p1, strlen(p1), "HTLoadHTTP");
1.49      luotonen  198:            free(p1);
                    199:            return status;   /* No such host for example */
                    200:        }
1.1       timbl     201:         free(p1);
                    202:     }
                    203:     
1.15      luotonen  204: /*
                    205: ** Compose authorization information (this was moved here
                    206: ** from after the making of the connection so that the connection
                    207: ** wouldn't have to wait while prompting username and password
                    208: ** from the user).                             -- AL 13.10.93
                    209: */
                    210: #ifdef ACCESS_AUTH
1.21      luotonen  211:     HTAA_composeAuth(request);
                    212:     if (TRACE) {
                    213:        if (request->authorization)
                    214:            fprintf(stderr, "HTTP: Sending Authorization: %s\n",
                    215:                    request->authorization);
                    216:        else
                    217:            fprintf(stderr, "HTTP: Not sending authorization (yet)\n");
1.15      luotonen  218:     }
                    219: #endif /* ACCESS_AUTH */
1.1       timbl     220:    
1.10      timbl     221: /*     Now, let's get a socket set up from the server for the data:
1.1       timbl     222: */      
                    223: #ifdef DECNET
                    224:     s = socket(AF_DECnet, SOCK_STREAM, 0);
                    225: #else
                    226:     s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
                    227: #endif
                    228:     status = connect(s, (struct sockaddr*)&soc_address, sizeof(soc_address));
                    229:     if (status < 0) {
                    230:            if (TRACE) fprintf(stderr, 
1.30      frystyk   231:              "HTTP: Unable to connect to remote host for `%s' (errno = %d).\n",
                    232:              arg, errno);
1.54    ! luotonen  233: #if 0
1.51      luotonen  234:            HTAddError2(request,"Unable to connect to remote host:",
                    235:                        HTErrnoString());
1.54    ! luotonen  236: #endif
        !           237:            HTErrorSysAdd(request, ERR_FATAL, NO, "connect");
1.1       timbl     238:            return HTInetStatus("connect");
                    239:       }
                    240:     
                    241:     if (TRACE) fprintf(stderr, "HTTP connected, socket %d\n", s);
                    242: 
1.17      timbl     243: 
                    244: /*     Compose and send command
                    245: **     ------------------------
                    246: */
                    247:     {
                    248:         char *command;                 /* The whole command */
                    249:        
1.1       timbl     250: /*     Ask that node for the document,
                    251: **     omitting the host name & anchor if not gatewayed.
                    252: */        
1.37      luotonen  253:        if (gate) { /* This is no longer used, and could be thrown away */
1.17      timbl     254:            command = malloc(4 + strlen(arg)+ 2 + 31);
                    255:            if (command == NULL) outofmem(__FILE__, "HTLoadHTTP");
                    256:            strcpy(command, "GET ");
                    257:            strcat(command, arg);
                    258:        } else { /* not gatewayed */
                    259:            char * p1 = HTParse(arg, "", PARSE_PATH|PARSE_PUNCTUATION);
                    260:            command = malloc(4 + strlen(p1)+ 2 + 31);
                    261:            if (command == NULL) outofmem(__FILE__, "HTLoadHTTP");
1.23      luotonen  262:            if (request->method != METHOD_INVALID) {
                    263:                strcpy(command, HTMethod_name(request->method));
1.22      luotonen  264:                strcat(command, " ");
                    265:            }
                    266:            else {
                    267:                strcpy(command, "GET ");
                    268:            }
1.37      luotonen  269:            /* if we are using a proxy gateway don't copy in the first slash
                    270:            ** of say: /gopher://a;lkdjfl;ajdf;lkj/;aldk/adflj
                    271:            ** so that just gohper://.... is sent.
                    272:            */
                    273:            if (using_proxy)
                    274:                strcat(command, p1+1);
                    275:            else
                    276:                strcat(command, p1);
1.17      timbl     277:            free(p1);
                    278:        }
1.2       timbl     279: #ifdef HTTP2
1.17      timbl     280:        if (extensions) {
                    281:            strcat(command, " ");
                    282:            strcat(command, HTTP_VERSION);
                    283:        }
1.2       timbl     284: #endif
1.17      timbl     285:     
                    286:        strcat(command, crlf);  /* CR LF, as in rfc 977 */
                    287:     
1.37      luotonen  288:        if (extensions && HTImProxy && HTProxyHeaders) {
                    289:            StrAllocCat(command, HTProxyHeaders);
                    290:        }
                    291:        else if (extensions) {
1.21      luotonen  292: 
1.17      timbl     293:            int i;
                    294:            HTAtom * present = WWW_PRESENT;
                    295:            char line[256];    /*@@@@ */
1.21      luotonen  296:            HTList *conversions[2];
                    297: 
1.22      luotonen  298:            if (!HTConversions) {
                    299:                HTConversions = HTList_new();
1.34      frystyk   300: /*             HTFormatInit(HTConversions);    App may do this not us tbl940210 */
1.22      luotonen  301:            }
1.28      timbl     302: 
1.21      luotonen  303:            conversions[0] = HTConversions;
                    304:            conversions[1] = request->conversions;
                    305: 
1.34      frystyk   306:            
1.21      luotonen  307:            for (i=0; i<2; i++) {
                    308:                HTList *cur = conversions[i];
                    309:                HTPresentation *pres;
                    310: 
                    311:                while ((pres = (HTPresentation*)HTList_nextObject(cur))) {
                    312:                    if (pres->rep_out == present) {
                    313:                        if (pres->quality != 1.0) {
1.35      frystyk   314:                            sprintf(line, "Accept: %s; q=%.3f%c%c",
1.21      luotonen  315:                                    HTAtom_name(pres->rep),
                    316:                                    pres->quality, CR, LF);
                    317:                        } else {
                    318:                            sprintf(line, "Accept: %s%c%c",
                    319:                                    HTAtom_name(pres->rep), CR, LF);
                    320:                        }
                    321:                        StrAllocCat(command, line);
1.17      timbl     322:                    }
                    323:                }
1.2       timbl     324:            }
1.22      luotonen  325: 
1.37      luotonen  326:            sprintf(line, "User-Agent: %s/%s  libwww/%s%c%c",
1.17      timbl     327:                    HTAppName ? HTAppName : "unknown",
                    328:                    HTAppVersion ? HTAppVersion : "0.0",
                    329:                    HTLibraryVersion, CR, LF);
1.37      luotonen  330:            StrAllocCat(command, line);
1.45      luotonen  331: 
                    332: #ifdef ACCESS_AUTH
                    333:            if (request->authorization != NULL) {
                    334:                sprintf(line, "Authorization: %s%c%c",
                    335:                        request->authorization, CR, LF);
                    336:                StrAllocCat(command, line);
                    337:            }
                    338: #endif /* ACCESS_AUTH */
                    339: 
1.37      luotonen  340:        }
1.22      luotonen  341: 
1.17      timbl     342:        StrAllocCat(command, crlf);     /* Blank line means "end" */
                    343:     
                    344:        if (TRACE) fprintf(stderr, "HTTP Tx: %s\n", command);
                    345:     
                    346:     /* Translate into ASCII if necessary
                    347:     */
1.4       timbl     348: #ifdef NOT_ASCII
1.17      timbl     349:        {
                    350:            char * p;
                    351:            for(p = command; *p; p++) {
                    352:                *p = TOASCII(*p);
                    353:            }
1.1       timbl     354:        }
1.3       timbl     355: #endif
1.17      timbl     356:     
                    357:        status = NETWRITE(s, command, (int)strlen(command));
                    358:        free(command);
                    359:        if (status<0) {
                    360:            if (TRACE) fprintf(stderr,
                    361:                "HTTPAccess: Unable to send command.\n");
1.54    ! luotonen  362: #if 0
1.51      luotonen  363:            HTAddError2(request,"Couldn't send request:",HTErrnoString());
1.54    ! luotonen  364: #endif
        !           365:            HTErrorSysAdd(request, ERR_FATAL, NO, "NETWRITE");
1.1       timbl     366:            return HTInetStatus("send");
1.17      timbl     367:        }
                    368:     } /* compose and send command */
                    369:     
1.2       timbl     370: 
1.17      timbl     371: /*     Read the response
                    372: **     -----------------
1.11      timbl     373: **
                    374: **     HTTP0 servers must return ASCII style text, though it can in
                    375: **     principle be just text without any markup at all.
                    376: **     Full HTTP servers must return a response
                    377: **     line and RFC822 style header.  The response must therefore in
                    378: **     either case have a CRLF somewhere soon.
                    379: **
                    380: **     This is the theory.  In practice, there are (1993) unfortunately
                    381: **     many binary documents just served up with HTTP0.9.  This
                    382: **     means we have to preserve the binary buffer (on the assumption that
                    383: **     conversion from ASCII may lose information) in case it turns
                    384: **     out that we want the binary original.
1.2       timbl     385: */
1.53      luotonen  386: 
                    387:     CTRACE(stderr, "Waiting..... for response\n");
                    388: 
1.37      luotonen  389:     if (HTImProxy) {
1.24      luotonen  390: 
1.22      luotonen  391:        /*
                    392:        ** Server as a gateway -- send body of the message
                    393:        ** received from client (if any).
                    394:        */
                    395:        if (request->isoc && request->content_length > 0) {
                    396:            int remain = request->content_length;
                    397:            int i = remain;
                    398:            char * buf;
                    399: 
                    400:            while (remain > 0  &&
                    401:                   (buf = HTInputSocket_getBlock(request->isoc, &i))) {
                    402:                int status = NETWRITE(s, buf, i);
                    403:                if (status < 0) {
1.27      luotonen  404:                    CTRACE(stderr, "HTTPAccess.. Unable to forward body\n");
1.54    ! luotonen  405: #if 0
1.51      luotonen  406:                    HTAddError2(request,"Couldn't forward message body:",
                    407:                                HTErrnoString());
1.54    ! luotonen  408: #endif
        !           409:                    HTErrorSysAdd(request,ERR_FATAL,NO,"NETWRITE");
1.22      luotonen  410:                    return HTInetStatus("send");
                    411:                }
                    412:                remain -= i;
                    413:                i = remain;
                    414:            }
                    415:        }
1.23      luotonen  416: 
                    417:        /*
1.22      luotonen  418:        ** Load results directly to client
                    419:        */
1.50      luotonen  420:        HTCopy(s, request->output_stream);
1.25      luotonen  421:        (*request->output_stream->isa->free)(request->output_stream);
1.37      luotonen  422: 
1.22      luotonen  423:        return HT_LOADED;
                    424:     }
                    425:     else {     /* read response */
1.21      luotonen  426: 
1.17      timbl     427:        HTFormat format_in;             /* Format arriving in the message */
1.21      luotonen  428:        HTInputSocket *isoc = HTInputSocket_new(s);
                    429:        char * status_line = HTInputSocket_getStatusLine(isoc);
1.2       timbl     430: 
1.11      timbl     431: /* Kludge to trap binary responses from illegal HTTP0.9 servers.
                    432: ** First time we have enough, look at the stub in ASCII
                    433: ** and get out of here if it doesn't look right.
                    434: **
                    435: ** We also check for characters above 128 in the first few bytes, and
                    436: ** if we find them we forget the html default.
                    437: **
                    438: ** Bugs: A HTTP0.9 server returning a document starting "HTTP/"
                    439: **     will be taken as a HTTP 1.0 server.  Failure.
                    440: **     An HTTP 0.9 server returning a binary document with
                    441: **     characters < 128 will be read as ASCII.
                    442: */
1.36      frystyk   443: 
                    444:        /* If HTTP 0 response, then DO NOT CACHE (Henrik 14/02-94) */
                    445:        if (!status_line) {     
1.21      luotonen  446:            if (HTInputSocket_seemsBinary(isoc)) {
                    447:                format_in = HTAtom_for("www/unknown");
                    448:            }
                    449:            else {
                    450:                format_in = WWW_HTML;
                    451:            }
1.46      frystyk   452:            cache_http = NO;    /* Do not cache */
1.21      luotonen  453:            goto copy;
                    454:        } /* end kludge */
                    455: 
                    456:        if (status_line) {      /* Decode full HTTP response */
                    457:            /*
                    458:            ** We now have a terminated server status line, and we have
                    459:            ** checked that it is most probably a legal one.  Parse it.
                    460:            */
                    461:            char server_version[VERSION_LENGTH+1];
                    462:            int server_status;
                    463: 
                    464:            if (TRACE)
                    465:                fprintf(stderr, "HTTP Status Line: Rx: %.70s\n", status_line);
1.17      timbl     466:     
1.21      luotonen  467:            sscanf(status_line, "%20s%d", server_version, &server_status);
1.2       timbl     468: 
1.21      luotonen  469:            format_in = HTAtom_for("www/mime");
1.7       timbl     470:     
1.21      luotonen  471:            switch (server_status / 100) {
1.2       timbl     472: 
1.21      luotonen  473:              default:          /* bad number */
                    474:                HTAlert("Unknown status reply from server!");
                    475:                break;
1.17      timbl     476:                    
1.21      luotonen  477:              case 3:           /* Various forms of redirection */
                    478:                HTAlert(
1.17      timbl     479:            "Redirection response from server is not handled by this client");
1.21      luotonen  480:                break;
1.17      timbl     481:                    
1.21      luotonen  482:              case 4:           /* Access Authorization problem */
1.14      luotonen  483: #ifdef ACCESS_AUTH
1.21      luotonen  484:                switch (server_status) {
                    485:                  case 401:
                    486:                    parse_401_headers(request, isoc);
                    487: 
                    488:                    if (TRACE) fprintf(stderr, "%s %d %s\n",
                    489:                                       "HTTP: close socket", s,
                    490:                                       "to retry with Access Authorization");
1.24      luotonen  491:                    if (HTAA_retryWithAuth(request, HTLoadHTTP)) {
1.21      luotonen  492:                        status = HT_LOADED;/* @@ THIS ONLY WORKS ON LINEMODE */
                    493:                        goto clean_up;
                    494:                    }
                    495:                    /* else falltrough */
                    496:                  default:
1.14      luotonen  497:                    {
1.21      luotonen  498:                        char *p1 = HTParse(gate ? gate : arg, "",
                    499:                                           PARSE_HOST);
                    500:                        char * message;
                    501: 
                    502:                        if (!(message = (char*)malloc(strlen(status_line) +
                    503:                                                      strlen(p1) + 100)))
                    504:                            outofmem(__FILE__, "HTTP 4xx status");
1.14      luotonen  505:                        sprintf(message,
1.21      luotonen  506:                                "HTTP server at %s replies:\n%s\n\n%s\n",
                    507:                                p1, status_line,
                    508:                                ((server_status == 401) 
                    509:                                 ? "Access Authorization package giving up.\n"
                    510:                                 : ""));
1.22      luotonen  511:                        status = HTLoadError(request, server_status, message);
1.14      luotonen  512:                        free(message);
                    513:                        free(p1);
                    514:                        goto clean_up;
                    515:                    }
1.21      luotonen  516:                } /* switch */
                    517:                goto clean_up;
                    518:                break;
                    519: #else
                    520:                /* case 4 without Access Authorization falls through */
                    521:                /* to case 5 (previously "I think I goofed").  -- AL */
                    522: #endif /* ACCESS_AUTH */
                    523: 
                    524:              case 5:           /* I think you goofed */
                    525:                {
                    526:                    char *p1 = HTParse(gate ? gate : arg, "", PARSE_HOST);
                    527:                    char * message = (char*)malloc(strlen(status_line) + 
                    528:                                                   strlen(p1) + 100);
                    529:                    if (!message) outofmem(__FILE__, "HTTP 5xx status");
                    530:                    sprintf(message,
                    531:                            "HTTP server at %s replies:\n%s", p1, status_line);
1.22      luotonen  532:                    status = HTLoadError(request, server_status, message);
1.21      luotonen  533:                    free(message);
                    534:                    free(p1);
                    535:                    goto clean_up;
                    536:                }
                    537:                break;
1.17      timbl     538:                    
1.21      luotonen  539:              case 2:           /* Good: Got MIME object */
                    540:                break;
1.17      timbl     541:     
1.21      luotonen  542:            } /* switch on response code */
1.17      timbl     543:            
1.21      luotonen  544:        } /* Full HTTP reply */
1.17      timbl     545:            
                    546:     
1.3       timbl     547: /*     Set up the stream stack to handle the body of the message
1.33      timbl     548: **
                    549: **     In the special case of user asking for source and the message
                    550: **     being in MIME, we force the MIME decoding to occur, as it is really
                    551: **     HTTP decoding.  If the user really wants the HTTP headers, he
                    552: **     can ask for them as www/mime.
1.3       timbl     553: */
1.21      luotonen  554: 
1.13      duns      555: copy:
1.21      luotonen  556: 
1.43      frystyk   557:        if ((format_in == WWW_MIME)
                    558:            && (request->output_format == WWW_SOURCE)) {
1.33      timbl     559:            target = HTMIMEConvert(request, NULL, format_in,
                    560:            request->output_format, request->output_stream);
                    561:        } else {
1.47      luotonen  562:            target = HTStreamStack(format_in, request, NO);
1.33      timbl     563:        }
                    564:        
1.17      timbl     565:        if (!target) {
                    566:            char buffer[1024];  /* @@@@@@@@ */
                    567:            sprintf(buffer, "Sorry, no known way of converting %s to %s.",
                    568:                    HTAtom_name(format_in), HTAtom_name(request->output_format));
                    569:            fprintf(stderr, "HTTP: %s", buffer);
1.22      luotonen  570:            status = HTLoadError(request, 501, buffer);
1.17      timbl     571:            goto clean_up;
                    572:        }
                    573:     
1.19      timbl     574:         /* @@ Bug: The decision of whether or not to cache should also be
1.21      luotonen  575:        ** made contingent on a IP address match or non match.
                    576:        */
1.48      timbl     577: 
                    578:         if (HTCacheDir && cache_http) {
1.19      timbl     579:            target = HTTee(target, HTCacheWriter(request, NULL, format_in,
1.21      luotonen  580:                                                 request->output_format,
                    581:                                                 request->output_stream));
1.19      timbl     582:        }
                    583:        
1.11      timbl     584: /*     Push the data down the stream
1.3       timbl     585: **     We have to remember the end of the first buffer we just read
1.2       timbl     586: */
1.30      frystyk   587:        if (format_in == WWW_HTML)  {  
1.17      timbl     588:            target = HTNetToText(target);       /* Pipe through CR stripper */
                    589:        }
1.21      luotonen  590: 
1.17      timbl     591:        (*target->isa->put_block)(target,
1.21      luotonen  592:                                  isoc->input_pointer,
                    593:                                  isoc->input_limit - isoc->input_pointer);
1.41      frystyk   594: 
1.17      timbl     595:        HTCopy(s, target);
                    596:            
                    597:        (*target->isa->free)(target);
                    598:        status = HT_LOADED;
1.11      timbl     599:     
1.2       timbl     600: /*     Clean up
1.1       timbl     601: */
1.17      timbl     602:        
                    603: clean_up: 
                    604:        if (TRACE) fprintf(stderr, "HTTP: close socket %d.\n", s);
                    605:        (void) NETCLOSE(s);
1.41      frystyk   606:        if (isoc)
                    607:            HTInputSocket_free(isoc);       
                    608:        if (status_line)
1.38      frystyk   609:            free(status_line);          /* Leak fix Henrik 18/02-94 */
                    610:        return status;                  /* Good return  */
1.3       timbl     611:     
1.17      timbl     612:     } /* read response */
                    613: } /* load HTTP */
1.1       timbl     614: 
                    615: /*     Protocol descriptor
                    616: */
                    617: 
1.17      timbl     618: GLOBALDEF PUBLIC HTProtocol HTTP = { "http", HTLoadHTTP, 0, 0 };
1.21      luotonen  619: 

Webmaster