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

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

Webmaster