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

1.74      frystyk     1: /*                                                                      HTTP.c
                      2: **     MULTITHREADED IMPLEMENTATION OF HTTP CLIENT
1.2       timbl       3: **
1.84      frystyk     4: **     (c) COPYRIGHT MIT 1995.
1.74      frystyk     5: **     Please first read the full copyright statement in the file COPYRIGH.
1.140.2.2! frystyk     6: **     @(#) $Id: HTTP.c,v 1.140.2.1 1996/10/29 21:27:21 eric Exp $
1.74      frystyk     7: **
                      8: **     This module implments the HTTP protocol as a state machine
1.55      frystyk     9: **
                     10: ** History:
1.59      frystyk    11: **    < May 24 94 ??   Unknown - but obviously written
1.56      frystyk    12: **     May 24 94 HF    Made reentrent and cleaned up a bit. Implemented
                     13: **                     Forward, redirection, error handling and referer field
1.67      duns       14: **      8 Jul 94  FM   Insulate free() from _free structure element.
1.71      frystyk    15: **     Jul 94 HFN      Written on top of HTTP.c, Henrik Frystyk
1.55      frystyk    16: **
1.1       timbl      17: */
                     18: 
1.78      frystyk    19: /* Library include files */
1.119     frystyk    20: #include "sysdep.h"
1.123     frystyk    21: #include "WWWUtil.h"
                     22: #include "WWWCore.h"
                     23: #include "WWWMIME.h"
                     24: #include "WWWStream.h"
1.125     frystyk    25: #include "WWWTrans.h"
1.94      frystyk    26: #include "HTReqMan.h"
1.95      frystyk    27: #include "HTNetMan.h"
1.109     frystyk    28: #include "HTTPUtil.h"
1.80      frystyk    29: #include "HTTPReq.h"
1.55      frystyk    30: #include "HTTP.h"                                             /* Implements */
1.140.2.1  eric       31: #include "HTWatch.h"
1.55      frystyk    32: 
                     33: /* Macros and other defines */
1.94      frystyk    34: #ifndef HTTP_PORT
                     35: #define HTTP_PORT 80   /* Allocated to http by Jon Postel/ISI 24-Jan-92 */
                     36: #endif
                     37: 
1.71      frystyk    38: #define PUTC(c)                (*me->target->isa->put_character)(me->target, c)
                     39: #define PUTS(s)                (*me->target->isa->put_string)(me->target, s)
                     40: #define PUTBLOCK(b, l) (*me->target->isa->put_block)(me->target, b, l)
                     41: #define FREE_TARGET    (*me->target->isa->_free)(me->target)
1.74      frystyk    42: #define ABORT_TARGET   (*me->target->isa->abort)(me->target, e)
1.2       timbl      43: 
1.140     frystyk    44: #define HTTP_DUMP
                     45: 
                     46: #ifdef HTTP_DUMP
1.139     frystyk    47: #define HTTP_OUTPUT    "w3chttp.out"
1.140     frystyk    48: PRIVATE FILE * htfp = NULL;
                     49: #endif
1.139     frystyk    50: 
1.59      frystyk    51: /* Type definitions and global variables etc. local to this module */
1.94      frystyk    52: 
                     53: /* Final states have negative value */
1.59      frystyk    54: typedef enum _HTTPState {
1.134     frystyk    55:     HTTP_ERROR         = -2,
                     56:     HTTP_OK            = -1,
1.71      frystyk    57:     HTTP_BEGIN         = 0,
                     58:     HTTP_NEED_CONNECTION,
1.140.2.1  eric       59:     HTTP_CONNECTED
1.59      frystyk    60: } HTTPState;
1.55      frystyk    61: 
1.94      frystyk    62: /* This is the context structure for the this module */
1.55      frystyk    63: typedef struct _http_info {
1.81      frystyk    64:     HTTPState          state;            /* Current State of the connection */
                     65:     HTTPState          next;                                  /* Next state */
1.134     frystyk    66:     int                        result;      /* Result to report to the after filter */
1.139     frystyk    67:     BOOL               lock;                           /* Block for writing */
1.140.2.1  eric       68:     HTNet *            net;
1.55      frystyk    69: } http_info;
                     70: 
1.88      frystyk    71: #define MAX_STATUS_LEN         100   /* Max nb of chars to check StatusLine */
1.55      frystyk    72: 
1.71      frystyk    73: struct _HTStream {
1.119     frystyk    74:     const HTStreamClass *      isa;
1.71      frystyk    75:     HTStream *                 target;
                     76:     HTRequest *                        request;
                     77:     http_info *                        http;
1.121     frystyk    78:     HTEOLState                 state;
1.71      frystyk    79:     BOOL                       transparent;
1.81      frystyk    80:     char *                     version;             /* Should we save this? */
1.71      frystyk    81:     int                                status;
1.81      frystyk    82:     char *                     reason;
1.71      frystyk    83:     char                       buffer[MAX_STATUS_LEN+1];
1.80      frystyk    84:     int                                buflen;
1.71      frystyk    85: };
1.21      luotonen   86: 
1.123     frystyk    87: struct _HTInputStream {
                     88:     const HTInputStreamClass * isa;
                     89: };
                     90: 
1.71      frystyk    91: /* ------------------------------------------------------------------------- */
                     92: /*                               Help Functions                             */
                     93: /* ------------------------------------------------------------------------- */
1.21      luotonen   94: 
1.94      frystyk    95: /*     HTTPCleanup
                     96: **     -----------
1.55      frystyk    97: **      This function closes the connection and frees memory.
1.94      frystyk    98: **      Returns YES on OK, else NO
1.1       timbl      99: */
1.94      frystyk   100: PRIVATE int HTTPCleanup (HTRequest *req, int status)
1.1       timbl     101: {
1.126     frystyk   102:     HTNet * net = HTRequest_net(req);
                    103:     http_info * http = (http_info *) HTNet_context(net);
                    104:     HTStream * input = HTRequest_inputStream(req);
1.80      frystyk   105: 
1.94      frystyk   106:     /* Free stream with data TO network */
1.112     frystyk   107:     if (HTRequest_isDestination(req))
                    108:        HTRequest_removeDestination(req);
1.126     frystyk   109:     else if (input) {
1.94      frystyk   110:        if (status == HT_INTERRUPTED)
1.126     frystyk   111:            (*input->isa->abort)(input, NULL);
1.94      frystyk   112:        else
1.126     frystyk   113:            (*input->isa->_free)(input);
                    114:        HTRequest_setInputStream(req, NULL);
1.94      frystyk   115:     }
1.88      frystyk   116: 
1.140     frystyk   117: #ifdef HTTP_DUMP
                    118:     if (htfp) {
                    119:        fclose(htfp);
                    120:        htfp = NULL;
                    121:     }
                    122: #endif
                    123: 
1.94      frystyk   124:     /* Remove the request object and our own context structure for http */
1.133     frystyk   125:     HT_FREE(http);
                    126:     HTNet_setContext(net, NULL);
1.131     frystyk   127:     HTNet_delete(net, status);
1.94      frystyk   128:     return YES;
1.55      frystyk   129: }
                    130: 
1.71      frystyk   131: /*
1.130     frystyk   132: **     Informational 1xx codes are handled separately
1.136     frystyk   133: **     Returns YES if we should continue, NO if we should stop
1.55      frystyk   134: */
1.130     frystyk   135: PRIVATE BOOL HTTPInformation (HTStream * me)
1.55      frystyk   136: {
1.136     frystyk   137:     http_info * http = me->http;
1.71      frystyk   138:     switch (me->status) {
                    139: 
1.136     frystyk   140:     case 100:
                    141:        HTRequest_addError(me->request, ERR_INFO, NO, HTERR_CONTINUE,
                    142:                           me->reason, (int) strlen(me->reason),
                    143:                           "HTTPInformation");
                    144:        return YES;
                    145:        break;
                    146: 
1.130     frystyk   147:     case 101:
1.136     frystyk   148:        /*
                    149:        **  We consider 101 Switching as a final state and exit this request
                    150:        */
1.130     frystyk   151:        HTRequest_addError(me->request, ERR_INFO, NO, HTERR_SWITCHING,
1.127     frystyk   152:                           me->reason, (int) strlen(me->reason),
1.130     frystyk   153:                           "HTTPInformation");
1.136     frystyk   154:        http->next = HTTP_OK;
                    155:        http->result = HT_UPGRADE;
1.127     frystyk   156:        break;
                    157: 
1.130     frystyk   158:     default:
1.136     frystyk   159:        HTRequest_addError(me->request, ERR_FATAL, NO, HTERR_BAD_REPLY,
                    160:                   (void *) me->buffer, me->buflen, "HTTPNextState");
                    161:        http->next = HTTP_ERROR;
                    162:        http->result = HT_ERROR;
1.127     frystyk   163:        break;
1.130     frystyk   164:     }
1.136     frystyk   165:     return NO;
1.130     frystyk   166: }
                    167: 
                    168: /*
                    169: **     This is a big switch handling all HTTP return codes. It puts in any
                    170: **     appropiate error message and decides whether we should expect data
                    171: **     or not.
                    172: */
                    173: PRIVATE void HTTPNextState (HTStream * me)
                    174: {
1.134     frystyk   175:     http_info * http = me->http;
1.130     frystyk   176:     switch (me->status) {
1.127     frystyk   177: 
1.78      frystyk   178:       case 0:                                               /* 0.9 response */
1.127     frystyk   179:       case 200:                                                               /* OK */
                    180:        HTRequest_addError(me->request, ERR_INFO, NO, HTERR_OK,
                    181:                           me->reason, (int) strlen(me->reason),
                    182:                           "HTTPNextState");
1.134     frystyk   183:        http->next = HTTP_OK;
                    184:        http->result = HT_LOADED;
1.112     frystyk   185:        break;
                    186: 
1.127     frystyk   187:       case 201:                                                          /* Created */
1.112     frystyk   188:        HTRequest_addError(me->request, ERR_INFO, NO, HTERR_CREATED,
                    189:                           me->reason, (int) strlen(me->reason),
                    190:                           "HTTPNextState");
1.134     frystyk   191:        http->next = HTTP_OK;
                    192:        http->result = HT_CREATED;
1.112     frystyk   193:        break;
                    194: 
1.127     frystyk   195:       case 202:                                                         /* Accepted */
1.112     frystyk   196:        HTRequest_addError(me->request, ERR_INFO, NO, HTERR_ACCEPTED,
                    197:                           me->reason, (int) strlen(me->reason),
                    198:                           "HTTPNextState");
1.134     frystyk   199:        http->next = HTTP_OK;
                    200:        http->result = HT_ACCEPTED;
1.112     frystyk   201:        break;
                    202: 
1.127     frystyk   203:       case 203:                                    /* Non-authoritative information */
                    204:        HTRequest_addError(me->request, ERR_INFO, NO, HTERR_NON_AUTHORITATIVE,
1.112     frystyk   205:                           me->reason, (int) strlen(me->reason),
                    206:                           "HTTPNextState");
1.134     frystyk   207:        http->next = HTTP_OK;
                    208:        http->result = HT_LOADED;
1.71      frystyk   209:        break;
1.78      frystyk   210: 
                    211:       case 204:                                                      /* No Response */
1.112     frystyk   212:        HTRequest_addError(me->request, ERR_INFO, NO, HTERR_NO_CONTENT,
                    213:                           me->reason, (int) strlen(me->reason),
                    214:                           "HTTPNextState");
1.134     frystyk   215:        http->next = HTTP_OK;
                    216:        http->result = HT_NO_DATA;
                    217:        break;
                    218: 
                    219:       case 205:                                                    /* Reset Content */
                    220:        HTRequest_addError(me->request, ERR_INFO, NO, HTERR_RESET,
                    221:                           me->reason, (int) strlen(me->reason),
                    222:                           "HTTPNextState");
                    223:        http->next = HTTP_OK;
                    224:        http->result = HT_RESET_CONTENT;
                    225:        break;
                    226: 
                    227:       case 206:                                                  /* Partial Content */
                    228:        HTRequest_addError(me->request, ERR_INFO, NO, HTERR_PARTIAL,
                    229:                           me->reason, (int) strlen(me->reason),
                    230:                           "HTTPNextState");
                    231:        http->next = HTTP_OK;
                    232:        http->result = HT_PARTIAL_CONTENT;
                    233:        break;
                    234: 
                    235:       case 300:                                                 /* Multiple Choices */
                    236:        HTRequest_addError(me->request, ERR_INFO, NO, HTERR_MULTIPLE,
                    237:                           me->reason, (int) strlen(me->reason),
                    238:                           "HTTPNextState");
                    239:        http->next = HTTP_OK;
                    240:        http->result = HT_LOADED;
1.71      frystyk   241:        break;
1.78      frystyk   242: 
1.71      frystyk   243:       case 301:                                                            /* Moved */
1.112     frystyk   244:        HTRequest_addError(me->request, ERR_INFO, NO, HTERR_MOVED,
                    245:                           me->reason, (int) strlen(me->reason),
                    246:                           "HTTPNextState");
1.134     frystyk   247:        http->next = HTTP_ERROR;
                    248:        http->result = HT_PERM_REDIRECT;
1.112     frystyk   249:        break;
                    250: 
1.71      frystyk   251:       case 302:                                                            /* Found */
1.112     frystyk   252:        HTRequest_addError(me->request, ERR_INFO, NO, HTERR_FOUND,
                    253:                           me->reason, (int) strlen(me->reason),
                    254:                           "HTTPNextState");
1.134     frystyk   255:        http->next = HTTP_ERROR;
                    256:        http->result = HT_TEMP_REDIRECT;
1.71      frystyk   257:        break;
1.55      frystyk   258:        
1.71      frystyk   259:       case 303:                                                           /* Method */
1.107     frystyk   260:        HTRequest_addError(me->request, ERR_FATAL, NO, HTERR_NOT_IMPLEMENTED,
                    261:                           me->reason, (int) strlen(me->reason),
                    262:                           "HTTPNextState");
1.134     frystyk   263:        http->next = HTTP_ERROR;
                    264:        http->result = HT_SEE_OTHER;
1.71      frystyk   265:        break;
1.91      frystyk   266: 
                    267:       case 304:                                                     /* Not Modified */
1.131     frystyk   268:        HTRequest_addError(me->request, ERR_INFO, NO, HTERR_NOT_MODIFIED,
1.112     frystyk   269:                           me->reason, (int) strlen(me->reason),
                    270:                           "HTTPNextState");
1.135     frystyk   271:        http->next = HTTP_OK;
1.134     frystyk   272:        http->result = HT_NOT_MODIFIED;
                    273:        break;
                    274:        
                    275:       case 305:                                                        /* Use proxy */
                    276:        HTRequest_addError(me->request, ERR_INFO, NO, HTERR_USE_PROXY,
                    277:                           me->reason, (int) strlen(me->reason),
                    278:                           "HTTPNextState");
                    279:        http->next = HTTP_ERROR;
                    280:        http->result = HT_USE_PROXY;
1.91      frystyk   281:        break;
1.55      frystyk   282:        
1.78      frystyk   283:       case 400:                                                      /* Bad Request */
1.104     frystyk   284:        HTRequest_addError(me->request, ERR_FATAL, NO, HTERR_BAD_REQUEST,
1.100     frystyk   285:                   me->reason, (int) strlen(me->reason), "HTTPNextState");
1.134     frystyk   286:        http->next = HTTP_ERROR;
                    287:        http->result = HT_ERROR;
1.71      frystyk   288:        break;
1.70      howcome   289: 
1.71      frystyk   290:       case 401:
1.104     frystyk   291:        HTRequest_addError(me->request, ERR_FATAL, NO, HTERR_UNAUTHORIZED,
1.100     frystyk   292:                   me->reason, (int) strlen(me->reason), "HTTPNextState");
1.134     frystyk   293:        http->next = HTTP_ERROR;
                    294:        http->result = HT_NO_ACCESS;
1.71      frystyk   295:        break;
                    296:        
                    297:       case 402:                                                 /* Payment required */
1.104     frystyk   298:        HTRequest_addError(me->request, ERR_FATAL, NO, HTERR_PAYMENT_REQUIRED,
1.100     frystyk   299:                   me->reason, (int) strlen(me->reason), "HTTPNextState");
1.134     frystyk   300:        http->next = HTTP_ERROR;
                    301:        http->result = HT_ERROR;
1.71      frystyk   302:        break;
1.55      frystyk   303:        
1.71      frystyk   304:       case 403:                                                        /* Forbidden */
1.104     frystyk   305:        HTRequest_addError(me->request, ERR_FATAL, NO, HTERR_FORBIDDEN,
1.100     frystyk   306:                   me->reason, (int) strlen(me->reason), "HTTPNextState");
1.134     frystyk   307:        http->next = HTTP_ERROR;
                    308:        http->result = HT_FORBIDDEN;
1.71      frystyk   309:        break;
1.55      frystyk   310:        
1.71      frystyk   311:       case 404:                                                        /* Not Found */
1.104     frystyk   312:        HTRequest_addError(me->request, ERR_FATAL, NO, HTERR_NOT_FOUND,
1.100     frystyk   313:                   me->reason, (int) strlen(me->reason), "HTTPNextState");
1.134     frystyk   314:        http->next = HTTP_ERROR;
                    315:        http->result = HT_ERROR;
1.71      frystyk   316:        break;
                    317:        
1.78      frystyk   318:       case 405:                                                      /* Not Allowed */
1.104     frystyk   319:        HTRequest_addError(me->request, ERR_FATAL, NO, HTERR_NOT_ALLOWED,
1.100     frystyk   320:                   me->reason, (int) strlen(me->reason), "HTTPNextState");
1.134     frystyk   321:        http->next = HTTP_ERROR;
                    322:        http->result = HT_ERROR;
1.78      frystyk   323:        break;
                    324: 
                    325:       case 406:                                                  /* None Acceptable */
1.104     frystyk   326:        HTRequest_addError(me->request, ERR_FATAL, NO, HTERR_NONE_ACCEPTABLE,
1.100     frystyk   327:                   me->reason, (int) strlen(me->reason), "HTTPNextState");
1.134     frystyk   328:        http->next = HTTP_ERROR;
                    329:        http->result = HT_NOT_ACCEPTABLE;
1.78      frystyk   330:        break;
                    331: 
                    332:       case 407:                                    /* Proxy Authentication Required */
1.127     frystyk   333:        HTRequest_addError(me->request, ERR_FATAL, NO,HTERR_PROXY_UNAUTHORIZED,
1.100     frystyk   334:                   me->reason, (int) strlen(me->reason), "HTTPNextState");
1.134     frystyk   335:        http->next = HTTP_ERROR;
                    336:        http->result = HT_NO_PROXY_ACCESS;
1.78      frystyk   337:        break;
                    338: 
                    339:       case 408:                                                  /* Request Timeout */
1.104     frystyk   340:        HTRequest_addError(me->request, ERR_FATAL, NO, HTERR_TIMEOUT,
1.100     frystyk   341:                   me->reason, (int) strlen(me->reason), "HTTPNextState");
1.134     frystyk   342:        http->next = HTTP_ERROR;
                    343:        http->result = HT_ERROR;
                    344:        break;
                    345: 
                    346:       case 409:                                                         /* Conflict */
                    347:        HTRequest_addError(me->request, ERR_FATAL, NO, HTERR_CONFLICT,
                    348:                   me->reason, (int) strlen(me->reason), "HTTPNextState");
                    349:        http->next = HTTP_ERROR;
                    350:        http->result = HT_CONFLICT;
                    351:        break;
                    352: 
                    353:       case 410:                                                             /* Gone */
                    354:        HTRequest_addError(me->request, ERR_FATAL, NO, HTERR_GONE,
                    355:                   me->reason, (int) strlen(me->reason), "HTTPNextState");
                    356:        http->next = HTTP_ERROR;
                    357:        http->result = HT_ERROR;
                    358:        break;
                    359: 
                    360:       case 411:                                                  /* Length Required */
                    361:        HTRequest_addError(me->request, ERR_FATAL, NO, HTERR_LENGTH_REQUIRED,
                    362:                   me->reason, (int) strlen(me->reason), "HTTPNextState");
                    363:        http->next = HTTP_ERROR;
                    364:        http->result = HT_LENGTH_REQUIRED;
                    365:        break;
                    366: 
                    367:       case 412:                                              /* Precondition failed */
                    368:        HTRequest_addError(me->request, ERR_FATAL, NO, HTERR_PRECON_FAILED,
                    369:                   me->reason, (int) strlen(me->reason), "HTTPNextState");
                    370:        http->next = HTTP_ERROR;
                    371:        http->result = HT_ERROR;
                    372:        break;
                    373: 
                    374:       case 413:                                         /* Request entity too large */
                    375:        HTRequest_addError(me->request, ERR_FATAL, NO, HTERR_TOO_BIG,
                    376:                   me->reason, (int) strlen(me->reason), "HTTPNextState");
                    377:        http->next = HTTP_ERROR;
                    378:        http->result = HT_ERROR;
                    379:        break;
                    380: 
                    381:       case 414:                                             /* Request-URI too long */
                    382:        HTRequest_addError(me->request, ERR_FATAL, NO, HTERR_URI_TOO_BIG,
                    383:                   me->reason, (int) strlen(me->reason), "HTTPNextState");
                    384:        http->next = HTTP_ERROR;
                    385:        http->result = HT_ERROR;
                    386:        break;
                    387: 
                    388:       case 415:                                                      /* Unsupported */
                    389:        HTRequest_addError(me->request, ERR_FATAL, NO, HTERR_UNSUPPORTED,
                    390:                   me->reason, (int) strlen(me->reason), "HTTPNextState");
                    391:        http->next = HTTP_ERROR;
                    392:        http->result = HT_ERROR;
1.78      frystyk   393:        break;
                    394: 
1.71      frystyk   395:       case 500:
1.104     frystyk   396:        HTRequest_addError(me->request, ERR_FATAL, NO, HTERR_INTERNAL,
1.100     frystyk   397:                   me->reason, (int) strlen(me->reason), "HTTPNextState");
1.134     frystyk   398:        http->next = HTTP_ERROR;
                    399:        http->result = HT_ERROR;
1.78      frystyk   400:        break;
                    401:        
1.71      frystyk   402:       case 501:
1.104     frystyk   403:        HTRequest_addError(me->request, ERR_FATAL, NO, HTERR_NOT_IMPLEMENTED,
1.100     frystyk   404:                   me->reason, (int) strlen(me->reason), "HTTPNextState");
1.134     frystyk   405:        http->next = HTTP_ERROR;
                    406:        http->result = HT_ERROR;
1.78      frystyk   407:        break;
                    408: 
                    409:       case 502:
1.104     frystyk   410:        HTRequest_addError(me->request, ERR_FATAL, NO, HTERR_BAD_GATE,
1.100     frystyk   411:                   me->reason, (int) strlen(me->reason), "HTTPNextState");
1.134     frystyk   412:        http->next = HTTP_ERROR;
                    413:        http->result = HT_ERROR;
1.78      frystyk   414:        break;
                    415: 
                    416:       case 503:
1.104     frystyk   417:        HTRequest_addError(me->request, ERR_FATAL, NO, HTERR_DOWN,
1.100     frystyk   418:                   me->reason, (int) strlen(me->reason), "HTTPNextState");
1.134     frystyk   419:        http->next = HTTP_ERROR;
1.81      frystyk   420: 
1.140     frystyk   421:        /*
                    422:        ** If Retry-After header is found then return HT_RETRY else HT_ERROR.
                    423:        ** The caller may want to reissue the request at a later point in time.
                    424:        */
                    425:        {
                    426:            HTResponse * response = HTRequest_response(me->request);
                    427:            if (HTResponse_retryTime(response))
                    428:                http->result = HT_RETRY;
                    429:            else
                    430:                http->result = HT_ERROR;
                    431:        }
1.78      frystyk   432:        break;
                    433: 
                    434:       case 504:
1.104     frystyk   435:        HTRequest_addError(me->request, ERR_FATAL, NO, HTERR_GATE_TIMEOUT,
1.100     frystyk   436:                   me->reason, (int) strlen(me->reason), "HTTPNextState");
1.134     frystyk   437:         http->next = HTTP_ERROR;
                    438:        http->result = HT_ERROR;
                    439:        break;
                    440: 
                    441:       case 505:                                     /* Unsupported protocol version */
                    442:        HTRequest_addError(me->request, ERR_FATAL, NO, HTERR_BAD_VERSION,
                    443:                   me->reason, (int) strlen(me->reason), "HTTPNextState");
                    444:         http->next = HTTP_ERROR;
                    445:        http->result = HT_BAD_VERSION;
1.71      frystyk   446:        break;
1.78      frystyk   447: 
1.71      frystyk   448:       default:                                                /* bad number */
1.104     frystyk   449:        HTRequest_addError(me->request, ERR_FATAL, NO, HTERR_BAD_REPLY,
1.100     frystyk   450:                   (void *) me->buffer, me->buflen, "HTTPNextState");
1.134     frystyk   451:        http->next = HTTP_ERROR;
                    452:        http->result = HT_ERROR;
1.71      frystyk   453:        break;
1.55      frystyk   454:     }
                    455: }
                    456: 
1.71      frystyk   457: /* ------------------------------------------------------------------------- */
                    458: /*                         HTTP Status Line Stream                          */
                    459: /* ------------------------------------------------------------------------- */
1.55      frystyk   460: 
1.71      frystyk   461: /*
1.140.2.1  eric      462: **     Analyze the stream we have read. If it is a HTTP 1.0 or higher
1.71      frystyk   463: **     then create a MIME-stream, else create a Guess stream to find out
                    464: **     what the 0.9 server is sending. We need to copy the buffer as we don't
                    465: **     know if we can modify the contents or not.
1.78      frystyk   466: **
                    467: **     Stream handling is a function of the status code returned from the 
                    468: **     server:
                    469: **             200:     Use `output_stream' in HTRequest structure
1.94      frystyk   470: **             else:    Use `debug_stream' in HTRequest structure
1.80      frystyk   471: **
                    472: **     Return: YES if buffer should be written out. NO otherwise
1.56      frystyk   473: */
1.100     frystyk   474: PRIVATE int stream_pipe (HTStream * me)
1.56      frystyk   475: {
1.136     frystyk   476:     HTRequest * request = me->request;
                    477:     HTNet * net = HTRequest_net(request);
1.123     frystyk   478:     HTHost * host = HTNet_host(net);
1.140.2.1  eric      479: 
                    480:     HTHost_setConsumed(net->host, me->buflen);
1.80      frystyk   481:     if (me->target) {
                    482:        int status = PUTBLOCK(me->buffer, me->buflen);
                    483:        if (status == HT_OK)
                    484:            me->transparent = YES;
                    485:        return status;
1.136     frystyk   486:     } else if (HTRequest_isSource(request)&&!HTRequest_outputStream(request)) {
1.88      frystyk   487:        /*
                    488:        **  We need to wait for the destinations to get ready
                    489:        */
                    490:        return HT_WOULD_BLOCK;
1.80      frystyk   491:     }
1.88      frystyk   492:        
1.132     frystyk   493:     /*
                    494:     ** Just check for HTTP and not HTTP/ as NCSA server chokes on 1.1 replies
                    495:     ** Thanks to Markku Savela <msa@msa.tte.vtt.fi>
                    496:     */
                    497: #if 0
1.81      frystyk   498:     if (strncasecomp(me->buffer, "http/", 5)) {
1.132     frystyk   499: #else
                    500:     if (strncasecomp(me->buffer, "http", 4)) {
                    501: #endif
1.80      frystyk   502:        int status;
1.136     frystyk   503:        HTRequest_addError(request, ERR_INFO, NO, HTERR_HTTP09,
1.80      frystyk   504:                   (void *) me->buffer, me->buflen, "HTTPStatusStream");
1.136     frystyk   505:        me->target = HTStreamStack(WWW_UNKNOWN,
                    506:                                   HTRequest_outputFormat(request),
                    507:                                   HTRequest_outputStream(request),
                    508:                                   request, NO);
1.134     frystyk   509:        me->http->next = HTTP_OK;
1.80      frystyk   510:        if ((status = PUTBLOCK(me->buffer, me->buflen)) == HT_OK)
                    511:            me->transparent = YES;
1.123     frystyk   512:        HTHost_setVersion(host, HTTP_09);
1.80      frystyk   513:        return status;
                    514:     } else {
1.140     frystyk   515:        HTResponse * response = HTRequest_response(request);
1.133     frystyk   516:        char *ptr = me->buffer+4;                      /* Skip the HTTP part */
1.81      frystyk   517:        me->version = HTNextField(&ptr);
1.95      frystyk   518: 
1.130     frystyk   519:        /* Here we want to find out when to use persistent connection */
1.133     frystyk   520:        if (!strncasecomp(me->version, "/1.0", 4)) {
1.128     frystyk   521:            if (PROT_TRACE)HTTrace("HTTP Status. This is a HTTP/1.0 server\n");
                    522:            HTHost_setVersion(host, HTTP_10);
1.133     frystyk   523:        } else if (!strncasecomp(me->version, "/1.", 3)) {     /* 1.x family */
1.128     frystyk   524:            HTHost_setVersion(host, HTTP_11);
1.133     frystyk   525:            HTNet_setPersistent(net, YES, HT_TP_INTERLEAVE);   /* By default */
                    526:        } else { 
                    527:            if (PROT_TRACE)HTTrace("HTTP Status. No 1.x version number - treat it as a HTTP/1.0 server\n");
                    528:            HTHost_setVersion(host, HTTP_10);
1.128     frystyk   529:        }
1.95      frystyk   530: 
1.81      frystyk   531:        me->status = atoi(HTNextField(&ptr));
1.133     frystyk   532:        /* Kludge to fix the NCSA server version bug */
                    533:        if (me->status == 0) me->status = atoi(me->version);
                    534: 
1.81      frystyk   535:        me->reason = ptr;
                    536:        if ((ptr = strchr(me->reason, '\r')) != NULL)     /* Strip \r and \n */
                    537:            *ptr = '\0';
                    538:        else if ((ptr = strchr(me->reason, '\n')) != NULL)
                    539:            *ptr = '\0';
                    540: 
1.130     frystyk   541:        /* 
                    542:        **  If it is a 1xx code then find out what to do and return until we
                    543:        **  get the next code. In the case of Upgrade we may not get back here
                    544:        **  at all. If we are uploading an entity then continue doing that
                    545:        */
                    546:        if (me->status/100 == 1) {
1.136     frystyk   547:            if (HTTPInformation(me) == YES) {
                    548:                me->buflen = 0;
                    549:                me->state = EOL_BEGIN;
                    550:                return HTMethod_hasEntity(HTRequest_method(request)) ?
                    551:                    HT_CONTINUE : HT_OK;
1.103     frystyk   552:            }
1.56      frystyk   553:        }
1.133     frystyk   554: 
                    555:        /*
                    556:        **  As we are getting fresh metainformation in the HTTP response,
                    557:        **  we clear the old metainfomation in order not to mix it with the new
                    558:        **  one. This is particularly important for the content-length and the
1.139     frystyk   559:        **  like. The TRACE and OPTIONS method just adds to the current 
                    560:        **  metainformation so in that case we don't clear the anchor.
1.133     frystyk   561:        */
1.136     frystyk   562:        if (me->status==200 || me->status==203 || me->status==300) {
1.140     frystyk   563:            /*
                    564:            **  200, 203 and 300 are all fully cacheable responses. No byte 
                    565:            **  ranges or anything else make life hard in this case.
                    566:            */
                    567:            HTResponse_setCachable(response, YES);
1.136     frystyk   568:            me->target = HTStreamStack(WWW_MIME,
                    569:                                       HTRequest_outputFormat(request),
                    570:                                       HTRequest_outputStream(request),
                    571:                                       request, NO);
1.140     frystyk   572:        } else if (me->status==206) {
                    573:            /*
                    574:            **  We got a partial response and now we must check whether
                    575:            **  we issued a cache If-Range request or it was a new 
                    576:            **  partial response which we don't have in cache. In the latter
                    577:            **  case, we don't cache the object and in the former we append
                    578:            **  the result to the already existing cache entry.
                    579:            */
                    580:            HTReload reload = HTRequest_reloadMode(request);
                    581:            if (reload == HT_CACHE_RANGE_VALIDATE) {
                    582:                HTResponse_setCachable(response, YES);
                    583:                me->target = HTStreamStack(WWW_MIME_PART,
                    584:                                           HTRequest_outputFormat(request),
                    585:                                           HTRequest_outputStream(request),
                    586:                                           request, NO);
                    587:            } else {
                    588:                me->target = HTStreamStack(WWW_MIME,
                    589:                                           HTRequest_outputFormat(request),
                    590:                                           HTRequest_outputStream(request),
                    591:                                           request, NO);
                    592:            }
1.139     frystyk   593:        } else if (me->status==204 || me->status==304) {
1.140     frystyk   594:            HTResponse_setCachable(response, YES);
1.136     frystyk   595:            me->target = HTStreamStack(WWW_MIME_HEAD,
                    596:                                       HTRequest_debugFormat(request),
                    597:                                       HTRequest_debugStream(request),
                    598:                                       request, NO);
                    599:        } else if (HTRequest_debugStream(request)) {
                    600:            me->target = HTStreamStack(WWW_MIME,
                    601:                                       HTRequest_debugFormat(request),
                    602:                                       HTRequest_debugStream(request),
                    603:                                       request, NO);
                    604:        } else {
1.140     frystyk   605:            /*
                    606:            **  We still need to parse the MIME part in order to find any
                    607:            **  valuable meta information which is needed from the response.
                    608:            */
1.136     frystyk   609:            me->target = HTStreamStack(WWW_MIME,
                    610:                                       HTRequest_debugFormat(request),
                    611:                                       HTRequest_debugStream(request),
                    612:                                       request, NO);
1.133     frystyk   613:        }
1.56      frystyk   614:     }
1.113     frystyk   615:     if (!me->target) me->target = HTErrorStream();
1.81      frystyk   616:     HTTPNextState(me);                                    /* Get next state */
1.80      frystyk   617:     me->transparent = YES;
                    618:     return HT_OK;
1.71      frystyk   619: }
1.56      frystyk   620: 
1.80      frystyk   621: /*
                    622: **     Searches for HTTP header line until buffer fills up or a CRLF or LF
                    623: **     is found
                    624: */
1.119     frystyk   625: PRIVATE int HTTPStatus_put_block (HTStream * me, const char * b, int l)
1.71      frystyk   626: {
1.80      frystyk   627:     while (!me->transparent && l-- > 0) {
                    628:        int status;
                    629:        if (me->target) {
                    630:            if ((status = stream_pipe(me)) != HT_OK)
                    631:                return status;
                    632:        } else {
                    633:            *(me->buffer+me->buflen++) = *b;
                    634:            if (me->state == EOL_FCR) {
                    635:                if (*b == LF) { /* Line found */
                    636:                    if ((status = stream_pipe(me)) != HT_OK)
                    637:                        return status;
                    638:                } else {
                    639:                    me->state = EOL_BEGIN;
                    640:                }
                    641:            } else if (*b == CR) {
                    642:                me->state = EOL_FCR;
                    643:            } else if (*b == LF) {
                    644:                if ((status = stream_pipe(me)) != HT_OK)
                    645:                    return status;
1.71      frystyk   646:            } else {
1.80      frystyk   647:                if (me->buflen >= MAX_STATUS_LEN) {
                    648:                    if ((status = stream_pipe(me)) != HT_OK)
                    649:                        return status;
                    650:                }
1.71      frystyk   651:            }
1.80      frystyk   652:            b++;
1.71      frystyk   653:        }
1.56      frystyk   654:     }
1.99      frystyk   655:     if (l > 0) return PUTBLOCK(b, l);
                    656:     return HT_OK;
1.56      frystyk   657: }
                    658: 
1.119     frystyk   659: PRIVATE int HTTPStatus_put_string (HTStream * me, const char * s)
1.71      frystyk   660: {
1.80      frystyk   661:     return HTTPStatus_put_block(me, s, (int) strlen(s));
1.71      frystyk   662: }
1.56      frystyk   663: 
1.100     frystyk   664: PRIVATE int HTTPStatus_put_character (HTStream * me, char c)
1.71      frystyk   665: {
1.80      frystyk   666:     return HTTPStatus_put_block(me, &c, 1);
                    667: }
                    668: 
1.100     frystyk   669: PRIVATE int HTTPStatus_flush (HTStream * me)
1.80      frystyk   670: {
                    671:     return (*me->target->isa->flush)(me->target);
1.71      frystyk   672: }
                    673: 
1.100     frystyk   674: PRIVATE int HTTPStatus_free (HTStream * me)
1.71      frystyk   675: {
1.87      frystyk   676:     int status = HT_OK;
                    677:     if (me->target) {
                    678:        if ((status = (*me->target->isa->_free)(me->target))==HT_WOULD_BLOCK)
                    679:            return HT_WOULD_BLOCK;
                    680:     }
1.115     frystyk   681:     HT_FREE(me);
1.100     frystyk   682:     return status;
1.71      frystyk   683: }
                    684: 
1.104     frystyk   685: PRIVATE int HTTPStatus_abort (HTStream * me, HTList * e)
1.71      frystyk   686: {
                    687:     if (me->target)
1.74      frystyk   688:        ABORT_TARGET;
1.115     frystyk   689:     HT_FREE(me);
1.74      frystyk   690:     if (PROT_TRACE)
1.116     eric      691:        HTTrace("HTTPStatus.. ABORTING...\n");
1.80      frystyk   692:     return HT_ERROR;
1.71      frystyk   693: }
                    694: 
                    695: /*     HTTPStatus Stream
                    696: **     -----------------
                    697: */
1.119     frystyk   698: PRIVATE const HTStreamClass HTTPStatusClass =
1.71      frystyk   699: {              
                    700:     "HTTPStatus",
1.80      frystyk   701:     HTTPStatus_flush,
1.71      frystyk   702:     HTTPStatus_free,
                    703:     HTTPStatus_abort,
                    704:     HTTPStatus_put_character,
                    705:     HTTPStatus_put_string,
                    706:     HTTPStatus_put_block
                    707: };
                    708: 
1.113     frystyk   709: PUBLIC HTStream * HTTPStatus_new (HTRequest *  request,
                    710:                                  void *        param,
                    711:                                  HTFormat      input_format,
                    712:                                  HTFormat      output_format,
                    713:                                  HTStream *    output_stream)
1.71      frystyk   714: {
1.115     frystyk   715:     HTStream * me;
                    716:     if ((me = (HTStream  *) HT_CALLOC(1, sizeof(HTStream))) == NULL)
                    717:         HT_OUTOFMEM("HTTPStatus_new");
1.71      frystyk   718:     me->isa = &HTTPStatusClass;
1.113     frystyk   719:     if (request) {
1.126     frystyk   720:        HTNet * net = HTRequest_net(request);
1.125     frystyk   721:         /* Get existing copy */
                    722:        http_info * http = (http_info *) HTNet_context(net);
1.113     frystyk   723:        me->request = request;
                    724:        me->http = http;
                    725:        http->next = HTTP_ERROR;
                    726:        me->state = EOL_BEGIN;
                    727:        return me;
                    728:     } else
                    729:        return HTErrorStream();
1.71      frystyk   730: }
                    731: 
                    732: /* ------------------------------------------------------------------------- */
                    733: 
                    734: /*             Load Document from HTTP Server                       HTLoadHTTP
1.55      frystyk   735: **             ==============================
                    736: **
                    737: **     Given a hypertext address, this routine loads a document.
                    738: **
                    739: ** On entry,
                    740: **      request                This is the request structure
1.94      frystyk   741: **     returns         HT_ERROR        Error has occured in call back
                    742: **                     HT_OK           Call back was OK
1.55      frystyk   743: */
1.140.2.1  eric      744: PRIVATE int HTTPEvent (SOCKET soc, void * pVoid, HTEvent_type type);
                    745: 
                    746: PUBLIC int HTLoadHTTP (SOCKET soc, HTRequest * request)
1.55      frystyk   747: {
                    748:     http_info *http;                       /* Specific protocol information */
1.112     frystyk   749:     HTParentAnchor *anchor = HTRequest_anchor(request);
1.140.2.1  eric      750:     HTNet * net = HTRequest_net(request);
1.112     frystyk   751: 
1.94      frystyk   752:     /*
                    753:     ** Initiate a new http structure and bind to request structure
                    754:     ** This is actually state HTTP_BEGIN, but it can't be in the state
                    755:     ** machine as we need the structure first.
                    756:     */
1.140.2.1  eric      757:     if (PROT_TRACE) HTTrace("HTTP........ Looking for `%s\'\n",
                    758:                            HTAnchor_physical(anchor));
                    759:     if ((http = (http_info *) HT_CALLOC(1, sizeof(http_info))) == NULL)
                    760:       HT_OUTOFMEM("HTLoadHTTP");
                    761:     http->state = HTTP_BEGIN;
                    762:     http->next = HTTP_OK;
                    763:     http->result = HT_ERROR;
                    764:     http->net = net;
                    765:     HTNet_setContext(net, http);
                    766:     HTNet_setEventCallback(net, HTTPEvent);
                    767:     HTNet_setEventParam(net, http);  /* callbacks get http* */
                    768: 
                    769:     return HTTPEvent(soc, http, HTEvent_NONE);         /* get it started - ops is ignored */
                    770: }
                    771: 
                    772: PRIVATE int HTTPEvent (SOCKET soc, void * pVoid, HTEvent_type type)
                    773: {
                    774:     http_info * http = (http_info *)pVoid;
                    775:     int status = HT_ERROR;
                    776:     HTNet * net = http->net;
                    777:     HTRequest * request = HTNet_request(net);
                    778:     HTParentAnchor *anchor = HTRequest_anchor(request);
                    779: 
1.71      frystyk   780:     /* Now jump into the machine. We know the state from the previous run */
                    781:     while (1) {
                    782:        switch (http->state) {
1.134     frystyk   783:        case HTTP_BEGIN:
1.129     frystyk   784:            http->state = HTTP_NEED_CONNECTION;
1.71      frystyk   785:            break;
                    786:            
1.123     frystyk   787:        case HTTP_NEED_CONNECTION:          /* Now let's set up a connection */
1.140.2.1  eric      788:            status = HTHost_connect(net->host, net, HTAnchor_physical(anchor), HTTP_PORT);
1.80      frystyk   789:            if (status == HT_OK) {
1.140     frystyk   790:                HTHost * host = HTNet_host(net);
                    791: 
1.123     frystyk   792:                /*
1.140     frystyk   793:                **  Check the protocol class to see if we have connected to a
                    794:                **  the right class of server, in this case HTTP. If we don't 
                    795:                **  know the server then assume a HTTP/1.0
1.123     frystyk   796:                */
                    797:                {
                    798:                    char * s_class = HTHost_class(host);
1.140     frystyk   799:                    if (!s_class) {
                    800:                        if (HTRequest_proxy(request) == NULL)
                    801:                            HTRequest_addConnection(request, "Keep-Alive", "");
                    802:                        HTHost_setClass(host, "http");
                    803:                    } else if (strcasecomp(s_class, "http")) {
1.123     frystyk   804:                        HTRequest_addError(request, ERR_FATAL, NO, HTERR_CLASS,
                    805:                                           NULL, 0, "HTLoadHTTP");
                    806:                        http->state = HTTP_ERROR;
                    807:                        break;
                    808:                    }
1.95      frystyk   809:                }
1.138     frystyk   810: 
1.123     frystyk   811:                /* 
                    812:                ** Create the stream pipe FROM the channel to the application.
                    813:                ** The target for the input stream pipe is set up using the
                    814:                ** stream stack.
1.113     frystyk   815:                */
1.140.2.2! frystyk   816:                {
        !           817:                    HTStream *me=HTStreamStack(WWW_HTTP,
        !           818:                                               HTRequest_outputFormat(request),
        !           819:                                               HTRequest_outputStream(request),
        !           820:                                               request, YES);
        !           821:                    HTNet_setReadStream(net, me);
        !           822:                    HTRequest_setOutputConnected(request, YES);
        !           823:                }
1.127     frystyk   824: 
1.123     frystyk   825:                /*
                    826:                ** Create the stream pipe TO the channel from the application
                    827:                ** and hook it up to the request object
                    828:                */
                    829:                {
1.140.2.2! frystyk   830:                    HTChannel * channel = HTHost_channel(net->host);
        !           831:                    HTOutputStream * output = HTChannel_output(channel);
1.140     frystyk   832:                    int version = HTHost_version(host);
1.139     frystyk   833:                    HTStream * app = NULL;
1.140.2.2! frystyk   834: 
        !           835:                    /*
        !           836:                    **  Instead of calling this directly we could have a 
        !           837:                    **  stream stack builder on the output stream as well
        !           838:                    */
        !           839: #ifdef HT_MUX
        !           840:                    output = (HTOutputStream *) HTMuxWriter_new(host, net, output);
        !           841: #endif
        !           842:                    
1.139     frystyk   843: #ifdef HTTP_DUMP
                    844:                    if (PROT_TRACE) {
1.140     frystyk   845:                        if ((htfp = fopen(HTTP_OUTPUT, "wb"))) {
                    846:                            output = (HTOutputStream *)
                    847:                                HTTee((HTStream *) output,
                    848:                                      HTFWriter_new(request, htfp, YES), NULL);
1.139     frystyk   849:                            HTTrace("HTTP........ Dumping request to `%s\'\n",
                    850:                                    HTTP_OUTPUT);
                    851:                        }
                    852:                    }   
                    853: #endif /* HTTP_DUMP */
                    854:                    app = HTMethod_hasEntity(HTRequest_method(request)) ?
                    855:                        HTMIMERequest_new(request,
1.140     frystyk   856:                            HTTPRequest_new(request, (HTStream *) output, NO,
                    857:                                            version),
                    858:                                          YES) :
                    859:                        HTTPRequest_new(request, (HTStream *) output, YES,
                    860:                                        version);
1.123     frystyk   861:                    HTRequest_setInputStream(request, app);
                    862:                }
1.88      frystyk   863: 
                    864:                /*
                    865:                ** Set up concurrent read/write if this request isn't the
                    866:                ** source for a PUT or POST. As source we don't start reading
                    867:                ** before all destinations are ready. If destination then
                    868:                ** register the input stream and get ready for read
                    869:                */
1.112     frystyk   870:                if (HTRequest_isDestination(request)) {
1.140.2.1  eric      871:                    HTHost_register(net->host, net, HTEvent_READ);
1.88      frystyk   872:                    HTRequest_linkDestination(request);
                    873:                }
1.140.2.1  eric      874:                http->state = HTTP_CONNECTED;
                    875:                type = HTEvent_WRITE;                       /* fresh, so try a write */
1.133     frystyk   876:            } else if (status == HT_WOULD_BLOCK || status == HT_PENDING)
1.94      frystyk   877:                return HT_OK;
1.71      frystyk   878:            else
                    879:                http->state = HTTP_ERROR;              /* Error or interrupt */
                    880:            break;
                    881: 
1.87      frystyk   882:            /* As we can do simultanous read and write this is now one state */
1.140.2.1  eric      883:          case HTTP_CONNECTED:
                    884:            if (type == HTEvent_WRITE) {
1.88      frystyk   885:                if (HTRequest_isDestination(request)) {
1.126     frystyk   886:                    HTRequest * source = HTRequest_source(request);
                    887:                    HTNet * srcnet = HTRequest_net(source);
1.112     frystyk   888:                    if (srcnet) {
1.140.2.1  eric      889:                        HTHost_register(srcnet->host, srcnet, HTEvent_READ);
                    890:                        HTHost_unregister(srcnet->host, srcnet, HTEvent_WRITE);
1.112     frystyk   891:                    }
1.94      frystyk   892:                    return HT_OK;
1.80      frystyk   893:                }
1.126     frystyk   894: 
                    895:                /*
                    896:                **  Should we use the input stream directly or call the post
                    897:                **  callback function to send data down to the network?
                    898:                */
                    899:                {
                    900:                    HTStream * input = HTRequest_inputStream(request);
                    901:                    HTPostCallback * pcbf = HTRequest_postCallback(request);
1.131     frystyk   902:                    if (pcbf) {
1.139     frystyk   903:                        if (http->lock)
                    904:                            return HT_OK;
                    905:                        else {
1.140.2.1  eric      906:                            status = (*pcbf)(request, input);
1.140     frystyk   907:                            if (status == HT_PAUSE || status == HT_LOADED) {
1.140.2.1  eric      908:                                type = HTEvent_READ;
1.139     frystyk   909:                                http->lock = YES;
1.140     frystyk   910:                            } else if (status == HT_ERROR) {
1.139     frystyk   911:                                http->result = HT_INTERRUPTED;
                    912:                                http->state = HTTP_ERROR;
                    913:                                break;
                    914:                            }
                    915:                        }
1.131     frystyk   916:                    } else {
1.140.2.1  eric      917:                        if (!HTHost_launchPending(net->host))
                    918:                            status = (*input->isa->flush)(input);
                    919:                        type = HTEvent_READ;
1.131     frystyk   920:                    }
                    921:                    if (status == HT_WOULD_BLOCK) return HT_OK;
1.126     frystyk   922:                }
1.140.2.1  eric      923:            } else if (type == HTEvent_READ) {
                    924:                status = HTHost_read(net->host);
1.131     frystyk   925:                if (status == HT_WOULD_BLOCK)
1.94      frystyk   926:                    return HT_OK;
1.131     frystyk   927:                else if (status == HT_CONTINUE) {
1.130     frystyk   928:                    if (PROT_TRACE) HTTrace("HTTP........ Continuing\n");
1.139     frystyk   929:                    http->lock = NO;
1.140.2.1  eric      930:                    type = HTEvent_WRITE;
1.130     frystyk   931:                    continue;
1.133     frystyk   932:                } else if (status==HT_LOADED)
1.140.2.1  eric      933:                    http->state = http->next;   /* Jump to next state (OK or ERROR) */
1.133     frystyk   934:                else if (status==HT_CLOSED) {
                    935:                    HTHost * host = HTNet_host(net);
                    936: 
                    937:                    /*
                    938:                    ** If this is a persistent connection and we get a close
                    939:                    ** then it is an error and we should recover from it by
                    940:                    ** restarting the pipe line of requests if any
                    941:                    */
                    942:                    if (HTHost_isPersistent(host)) {
1.135     frystyk   943:                        http->result = HT_RECOVER_PIPE;
1.133     frystyk   944:                        http->state = HTTP_ERROR;
                    945:                        break;
                    946:                    } else
1.134     frystyk   947:                        http->state = HTTP_OK;
1.133     frystyk   948:                } else
1.94      frystyk   949:                    http->state = HTTP_ERROR;
1.90      frystyk   950:            } else {
1.140.2.1  eric      951:                http->state = HTTP_ERROR;       /* don't know how to handle OOB */
1.90      frystyk   952:            }
1.71      frystyk   953:            break;
1.80      frystyk   954:            
1.134     frystyk   955:          case HTTP_OK:
1.88      frystyk   956:            if (HTRequest_isPostWeb(request)) {
1.91      frystyk   957:                if (HTRequest_isDestination(request)) {
1.126     frystyk   958:                    HTRequest * source = HTRequest_source(request);
1.91      frystyk   959:                    HTLink *link =
1.127     frystyk   960:                        HTLink_find((HTAnchor *)HTRequest_anchor(source),
1.112     frystyk   961:                                          (HTAnchor *) anchor);
1.109     frystyk   962:                    HTLink_setResult(link, HT_LINK_OK);
1.91      frystyk   963:                }
1.112     frystyk   964:            }
1.134     frystyk   965:            HTTPCleanup(request, http->result);
1.94      frystyk   966:            return HT_OK;
1.71      frystyk   967:            break;
1.80      frystyk   968:            
1.71      frystyk   969:          case HTTP_ERROR:
1.88      frystyk   970:            if (HTRequest_isPostWeb(request)) {
1.91      frystyk   971:                if (HTRequest_isDestination(request)) {
1.126     frystyk   972:                    HTRequest * source = HTRequest_source(request);
1.91      frystyk   973:                    HTLink *link =
1.127     frystyk   974:                        HTLink_find((HTAnchor *)HTRequest_anchor(source),
1.112     frystyk   975:                                          (HTAnchor *) anchor);
1.109     frystyk   976:                    HTLink_setResult(link, HT_LINK_ERROR);
1.91      frystyk   977:                }
1.112     frystyk   978:                HTRequest_killPostWeb(request);
                    979:            }
1.134     frystyk   980:            HTTPCleanup(request, http->result);
1.94      frystyk   981:            return HT_OK;
1.71      frystyk   982:            break;
                    983:        }
                    984:     } /* End of while(1) */
                    985: }    
1.88      frystyk   986: 
1.21      luotonen  987: 

Webmaster