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

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

Webmaster