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

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

Webmaster