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

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.153   ! frystyk     6: **     @(#) $Id: HTTP.c,v 1.152 1997/11/26 16:05:53 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) {
1.153   ! frystyk   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: 
1.152     frystyk   239:       case 207:                                                /* Partial Update OK */
                    240:        HTRequest_addError(me->request, ERR_INFO, NO, HTERR_PARTIAL_OK,
                    241:                           me->reason, (int) strlen(me->reason),
                    242:                           "HTTPNextState");
                    243:        http->next = HTTP_OK;
                    244:        http->result = HT_PARTIAL_CONTENT;
                    245:        break;
                    246: 
1.134     frystyk   247:       case 300:                                                 /* Multiple Choices */
                    248:        HTRequest_addError(me->request, ERR_INFO, NO, HTERR_MULTIPLE,
                    249:                           me->reason, (int) strlen(me->reason),
                    250:                           "HTTPNextState");
                    251:        http->next = HTTP_OK;
                    252:        http->result = HT_LOADED;
1.71      frystyk   253:        break;
1.78      frystyk   254: 
1.71      frystyk   255:       case 301:                                                            /* Moved */
1.112     frystyk   256:        HTRequest_addError(me->request, ERR_INFO, NO, HTERR_MOVED,
                    257:                           me->reason, (int) strlen(me->reason),
                    258:                           "HTTPNextState");
1.134     frystyk   259:        http->next = HTTP_ERROR;
                    260:        http->result = HT_PERM_REDIRECT;
1.112     frystyk   261:        break;
                    262: 
1.71      frystyk   263:       case 302:                                                            /* Found */
1.112     frystyk   264:        HTRequest_addError(me->request, ERR_INFO, NO, HTERR_FOUND,
                    265:                           me->reason, (int) strlen(me->reason),
                    266:                           "HTTPNextState");
1.134     frystyk   267:        http->next = HTTP_ERROR;
1.152     frystyk   268:        http->result = HT_FOUND;
1.71      frystyk   269:        break;
1.55      frystyk   270:        
1.71      frystyk   271:       case 303:                                                           /* Method */
1.152     frystyk   272:        HTRequest_addError(me->request, ERR_FATAL, NO, HTERR_METHOD,
1.107     frystyk   273:                           me->reason, (int) strlen(me->reason),
                    274:                           "HTTPNextState");
1.134     frystyk   275:        http->next = HTTP_ERROR;
                    276:        http->result = HT_SEE_OTHER;
1.71      frystyk   277:        break;
1.91      frystyk   278: 
                    279:       case 304:                                                     /* Not Modified */
1.131     frystyk   280:        HTRequest_addError(me->request, ERR_INFO, NO, HTERR_NOT_MODIFIED,
1.112     frystyk   281:                           me->reason, (int) strlen(me->reason),
                    282:                           "HTTPNextState");
1.135     frystyk   283:        http->next = HTTP_OK;
1.134     frystyk   284:        http->result = HT_NOT_MODIFIED;
                    285:        break;
                    286:        
                    287:       case 305:                                                        /* Use proxy */
                    288:        HTRequest_addError(me->request, ERR_INFO, NO, HTERR_USE_PROXY,
                    289:                           me->reason, (int) strlen(me->reason),
                    290:                           "HTTPNextState");
                    291:        http->next = HTTP_ERROR;
                    292:        http->result = HT_USE_PROXY;
1.91      frystyk   293:        break;
1.55      frystyk   294:        
1.152     frystyk   295: #if 0
                    296:       case 306:                                                        /* Use proxy */
                    297:        HTRequest_addError(me->request, ERR_INFO, NO, HTERR_PROXY_REDIRECT,
                    298:                           me->reason, (int) strlen(me->reason),
                    299:                           "HTTPNextState");
                    300:        http->next = HTTP_ERROR;
                    301:        http->result = HT_USE_PROXY;
                    302:        break;
                    303: #endif
                    304: 
                    305:       case 307:                                                        /* Use proxy */
                    306:        HTRequest_addError(me->request, ERR_INFO, NO, HTERR_TEMP_REDIRECT,
                    307:                           me->reason, (int) strlen(me->reason),
                    308:                           "HTTPNextState");
                    309:        http->next = HTTP_ERROR;
                    310:        http->result = HT_TEMP_REDIRECT;
                    311:        break;
                    312:        
1.78      frystyk   313:       case 400:                                                      /* Bad Request */
1.104     frystyk   314:        HTRequest_addError(me->request, ERR_FATAL, NO, HTERR_BAD_REQUEST,
1.100     frystyk   315:                   me->reason, (int) strlen(me->reason), "HTTPNextState");
1.134     frystyk   316:        http->next = HTTP_ERROR;
                    317:        http->result = HT_ERROR;
1.71      frystyk   318:        break;
1.70      howcome   319: 
1.71      frystyk   320:       case 401:
1.104     frystyk   321:        HTRequest_addError(me->request, ERR_FATAL, NO, HTERR_UNAUTHORIZED,
1.100     frystyk   322:                   me->reason, (int) strlen(me->reason), "HTTPNextState");
1.134     frystyk   323:        http->next = HTTP_ERROR;
                    324:        http->result = HT_NO_ACCESS;
1.71      frystyk   325:        break;
                    326:        
                    327:       case 402:                                                 /* Payment required */
1.104     frystyk   328:        HTRequest_addError(me->request, ERR_FATAL, NO, HTERR_PAYMENT_REQUIRED,
1.100     frystyk   329:                   me->reason, (int) strlen(me->reason), "HTTPNextState");
1.134     frystyk   330:        http->next = HTTP_ERROR;
                    331:        http->result = HT_ERROR;
1.71      frystyk   332:        break;
1.55      frystyk   333:        
1.71      frystyk   334:       case 403:                                                        /* Forbidden */
1.104     frystyk   335:        HTRequest_addError(me->request, ERR_FATAL, NO, HTERR_FORBIDDEN,
1.100     frystyk   336:                   me->reason, (int) strlen(me->reason), "HTTPNextState");
1.134     frystyk   337:        http->next = HTTP_ERROR;
                    338:        http->result = HT_FORBIDDEN;
1.71      frystyk   339:        break;
1.55      frystyk   340:        
1.71      frystyk   341:       case 404:                                                        /* Not Found */
1.104     frystyk   342:        HTRequest_addError(me->request, ERR_FATAL, NO, HTERR_NOT_FOUND,
1.100     frystyk   343:                   me->reason, (int) strlen(me->reason), "HTTPNextState");
1.134     frystyk   344:        http->next = HTTP_ERROR;
                    345:        http->result = HT_ERROR;
1.71      frystyk   346:        break;
                    347:        
1.78      frystyk   348:       case 405:                                                      /* Not Allowed */
1.104     frystyk   349:        HTRequest_addError(me->request, ERR_FATAL, NO, HTERR_NOT_ALLOWED,
1.100     frystyk   350:                   me->reason, (int) strlen(me->reason), "HTTPNextState");
1.134     frystyk   351:        http->next = HTTP_ERROR;
                    352:        http->result = HT_ERROR;
1.78      frystyk   353:        break;
                    354: 
                    355:       case 406:                                                  /* None Acceptable */
1.104     frystyk   356:        HTRequest_addError(me->request, ERR_FATAL, NO, HTERR_NONE_ACCEPTABLE,
1.100     frystyk   357:                   me->reason, (int) strlen(me->reason), "HTTPNextState");
1.134     frystyk   358:        http->next = HTTP_ERROR;
                    359:        http->result = HT_NOT_ACCEPTABLE;
1.78      frystyk   360:        break;
                    361: 
                    362:       case 407:                                    /* Proxy Authentication Required */
1.127     frystyk   363:        HTRequest_addError(me->request, ERR_FATAL, NO,HTERR_PROXY_UNAUTHORIZED,
1.100     frystyk   364:                   me->reason, (int) strlen(me->reason), "HTTPNextState");
1.134     frystyk   365:        http->next = HTTP_ERROR;
                    366:        http->result = HT_NO_PROXY_ACCESS;
1.78      frystyk   367:        break;
                    368: 
                    369:       case 408:                                                  /* Request Timeout */
1.104     frystyk   370:        HTRequest_addError(me->request, ERR_FATAL, NO, HTERR_TIMEOUT,
1.100     frystyk   371:                   me->reason, (int) strlen(me->reason), "HTTPNextState");
1.134     frystyk   372:        http->next = HTTP_ERROR;
                    373:        http->result = HT_ERROR;
                    374:        break;
                    375: 
                    376:       case 409:                                                         /* Conflict */
                    377:        HTRequest_addError(me->request, ERR_FATAL, NO, HTERR_CONFLICT,
                    378:                   me->reason, (int) strlen(me->reason), "HTTPNextState");
                    379:        http->next = HTTP_ERROR;
                    380:        http->result = HT_CONFLICT;
                    381:        break;
                    382: 
                    383:       case 410:                                                             /* Gone */
                    384:        HTRequest_addError(me->request, ERR_FATAL, NO, HTERR_GONE,
                    385:                   me->reason, (int) strlen(me->reason), "HTTPNextState");
                    386:        http->next = HTTP_ERROR;
                    387:        http->result = HT_ERROR;
                    388:        break;
                    389: 
                    390:       case 411:                                                  /* Length Required */
                    391:        HTRequest_addError(me->request, ERR_FATAL, NO, HTERR_LENGTH_REQUIRED,
                    392:                   me->reason, (int) strlen(me->reason), "HTTPNextState");
                    393:        http->next = HTTP_ERROR;
                    394:        http->result = HT_LENGTH_REQUIRED;
                    395:        break;
                    396: 
                    397:       case 412:                                              /* Precondition failed */
                    398:        HTRequest_addError(me->request, ERR_FATAL, NO, HTERR_PRECON_FAILED,
                    399:                   me->reason, (int) strlen(me->reason), "HTTPNextState");
                    400:        http->next = HTTP_ERROR;
                    401:        http->result = HT_ERROR;
                    402:        break;
                    403: 
                    404:       case 413:                                         /* Request entity too large */
                    405:        HTRequest_addError(me->request, ERR_FATAL, NO, HTERR_TOO_BIG,
                    406:                   me->reason, (int) strlen(me->reason), "HTTPNextState");
                    407:        http->next = HTTP_ERROR;
                    408:        http->result = HT_ERROR;
                    409:        break;
                    410: 
                    411:       case 414:                                             /* Request-URI too long */
                    412:        HTRequest_addError(me->request, ERR_FATAL, NO, HTERR_URI_TOO_BIG,
                    413:                   me->reason, (int) strlen(me->reason), "HTTPNextState");
                    414:        http->next = HTTP_ERROR;
                    415:        http->result = HT_ERROR;
                    416:        break;
                    417: 
                    418:       case 415:                                                      /* Unsupported */
                    419:        HTRequest_addError(me->request, ERR_FATAL, NO, HTERR_UNSUPPORTED,
                    420:                   me->reason, (int) strlen(me->reason), "HTTPNextState");
                    421:        http->next = HTTP_ERROR;
                    422:        http->result = HT_ERROR;
1.78      frystyk   423:        break;
                    424: 
1.152     frystyk   425:       case 416:                                    /* Request Range not satisfiable */
                    426:        HTRequest_addError(me->request, ERR_FATAL, NO, HTERR_BAD_RANGE,
                    427:                   me->reason, (int) strlen(me->reason), "HTTPNextState");
                    428:        http->next = HTTP_ERROR;
                    429:        http->result = HT_ERROR;
                    430:        break;
                    431: 
                    432:       case 417:                                               /* Expectation Failed */
                    433:        HTRequest_addError(me->request, ERR_FATAL, NO, HTERR_EXPECTATION_FAILED,
                    434:                   me->reason, (int) strlen(me->reason), "HTTPNextState");
                    435:        http->next = HTTP_ERROR;
                    436:        http->result = HT_ERROR;
                    437:        break;
                    438: 
                    439:       case 418:                                        /* Reauthentication required */
                    440:        HTRequest_addError(me->request, ERR_FATAL, NO, HTERR_REAUTH,
                    441:                   me->reason, (int) strlen(me->reason), "HTTPNextState");
                    442:        http->next = HTTP_ERROR;
                    443:        http->result = HT_ERROR;
                    444:        break;
                    445: 
                    446:       case 419:                                  /* Proxy Reauthentication required */
                    447:        HTRequest_addError(me->request, ERR_FATAL, NO, HTERR_PROXY_REAUTH,
                    448:                   me->reason, (int) strlen(me->reason), "HTTPNextState");
                    449:        http->next = HTTP_ERROR;
                    450:        http->result = HT_ERROR;
                    451:        break;
                    452: 
1.71      frystyk   453:       case 500:
1.104     frystyk   454:        HTRequest_addError(me->request, ERR_FATAL, NO, HTERR_INTERNAL,
1.100     frystyk   455:                   me->reason, (int) strlen(me->reason), "HTTPNextState");
1.134     frystyk   456:        http->next = HTTP_ERROR;
                    457:        http->result = HT_ERROR;
1.78      frystyk   458:        break;
                    459:        
1.71      frystyk   460:       case 501:
1.104     frystyk   461:        HTRequest_addError(me->request, ERR_FATAL, NO, HTERR_NOT_IMPLEMENTED,
1.100     frystyk   462:                   me->reason, (int) strlen(me->reason), "HTTPNextState");
1.134     frystyk   463:        http->next = HTTP_ERROR;
                    464:        http->result = HT_ERROR;
1.78      frystyk   465:        break;
                    466: 
                    467:       case 502:
1.104     frystyk   468:        HTRequest_addError(me->request, ERR_FATAL, NO, HTERR_BAD_GATE,
1.100     frystyk   469:                   me->reason, (int) strlen(me->reason), "HTTPNextState");
1.134     frystyk   470:        http->next = HTTP_ERROR;
                    471:        http->result = HT_ERROR;
1.78      frystyk   472:        break;
                    473: 
                    474:       case 503:
1.104     frystyk   475:        HTRequest_addError(me->request, ERR_FATAL, NO, HTERR_DOWN,
1.100     frystyk   476:                   me->reason, (int) strlen(me->reason), "HTTPNextState");
1.134     frystyk   477:        http->next = HTTP_ERROR;
1.81      frystyk   478: 
1.140     frystyk   479:        /*
                    480:        ** If Retry-After header is found then return HT_RETRY else HT_ERROR.
                    481:        ** The caller may want to reissue the request at a later point in time.
                    482:        */
                    483:        {
                    484:            HTResponse * response = HTRequest_response(me->request);
                    485:            if (HTResponse_retryTime(response))
                    486:                http->result = HT_RETRY;
                    487:            else
                    488:                http->result = HT_ERROR;
                    489:        }
1.78      frystyk   490:        break;
                    491: 
                    492:       case 504:
1.104     frystyk   493:        HTRequest_addError(me->request, ERR_FATAL, NO, HTERR_GATE_TIMEOUT,
1.100     frystyk   494:                   me->reason, (int) strlen(me->reason), "HTTPNextState");
1.134     frystyk   495:         http->next = HTTP_ERROR;
                    496:        http->result = HT_ERROR;
                    497:        break;
                    498: 
                    499:       case 505:                                     /* Unsupported protocol version */
                    500:        HTRequest_addError(me->request, ERR_FATAL, NO, HTERR_BAD_VERSION,
1.152     frystyk   501:                   me->reason, (int) strlen(me->reason), "HTTPNextState");
                    502:         http->next = HTTP_ERROR;
                    503:        http->result = HT_BAD_VERSION;
                    504:        break;
                    505: 
                    506:       case 506:                                   /* Partial update Not Implemented */
                    507:        HTRequest_addError(me->request, ERR_FATAL, NO, HTERR_NO_PARTIAL_UPDATE,
1.134     frystyk   508:                   me->reason, (int) strlen(me->reason), "HTTPNextState");
                    509:         http->next = HTTP_ERROR;
                    510:        http->result = HT_BAD_VERSION;
1.71      frystyk   511:        break;
1.78      frystyk   512: 
1.71      frystyk   513:       default:                                                /* bad number */
1.104     frystyk   514:        HTRequest_addError(me->request, ERR_FATAL, NO, HTERR_BAD_REPLY,
1.100     frystyk   515:                   (void *) me->buffer, me->buflen, "HTTPNextState");
1.134     frystyk   516:        http->next = HTTP_ERROR;
                    517:        http->result = HT_ERROR;
1.71      frystyk   518:        break;
1.55      frystyk   519:     }
                    520: }
                    521: 
1.71      frystyk   522: /* ------------------------------------------------------------------------- */
                    523: /*                         HTTP Status Line Stream                          */
                    524: /* ------------------------------------------------------------------------- */
1.55      frystyk   525: 
1.71      frystyk   526: /*
1.141     frystyk   527: **     Analyze the stream we have read. If it is a HTTP 1.0 or higher
1.71      frystyk   528: **     then create a MIME-stream, else create a Guess stream to find out
                    529: **     what the 0.9 server is sending. We need to copy the buffer as we don't
                    530: **     know if we can modify the contents or not.
1.78      frystyk   531: **
                    532: **     Stream handling is a function of the status code returned from the 
                    533: **     server:
                    534: **             200:     Use `output_stream' in HTRequest structure
1.94      frystyk   535: **             else:    Use `debug_stream' in HTRequest structure
1.80      frystyk   536: **
                    537: **     Return: YES if buffer should be written out. NO otherwise
1.56      frystyk   538: */
1.100     frystyk   539: PRIVATE int stream_pipe (HTStream * me)
1.56      frystyk   540: {
1.136     frystyk   541:     HTRequest * request = me->request;
                    542:     HTNet * net = HTRequest_net(request);
1.123     frystyk   543:     HTHost * host = HTNet_host(net);
1.141     frystyk   544: 
1.80      frystyk   545:     if (me->target) {
                    546:        int status = PUTBLOCK(me->buffer, me->buflen);
                    547:        if (status == HT_OK)
                    548:            me->transparent = YES;
                    549:        return status;
1.136     frystyk   550:     } else if (HTRequest_isSource(request)&&!HTRequest_outputStream(request)) {
1.88      frystyk   551:        /*
                    552:        **  We need to wait for the destinations to get ready
                    553:        */
                    554:        return HT_WOULD_BLOCK;
1.80      frystyk   555:     }
1.153   ! frystyk   556: 
        !           557: #if 0
        !           558:     {
        !           559:        char * uri = HTAnchor_address((HTAnchor *) HTRequest_anchor(request));
        !           560:        fprintf(stderr, "HTTP header: %s for '%s'\n", me->buffer, uri);
        !           561:        HT_FREE(uri);
        !           562:     }
        !           563: #endif
        !           564:     
1.132     frystyk   565:     /*
                    566:     ** Just check for HTTP and not HTTP/ as NCSA server chokes on 1.1 replies
                    567:     ** Thanks to Markku Savela <msa@msa.tte.vtt.fi>
1.141     frystyk   568: 
1.132     frystyk   569:     */
                    570: #if 0
1.81      frystyk   571:     if (strncasecomp(me->buffer, "http/", 5)) {
1.132     frystyk   572: #else
                    573:     if (strncasecomp(me->buffer, "http", 4)) {
                    574: #endif
1.80      frystyk   575:        int status;
1.136     frystyk   576:        HTRequest_addError(request, ERR_INFO, NO, HTERR_HTTP09,
1.80      frystyk   577:                   (void *) me->buffer, me->buflen, "HTTPStatusStream");
1.136     frystyk   578:        me->target = HTStreamStack(WWW_UNKNOWN,
                    579:                                   HTRequest_outputFormat(request),
                    580:                                   HTRequest_outputStream(request),
                    581:                                   request, NO);
1.134     frystyk   582:        me->http->next = HTTP_OK;
1.80      frystyk   583:        if ((status = PUTBLOCK(me->buffer, me->buflen)) == HT_OK)
                    584:            me->transparent = YES;
1.123     frystyk   585:        HTHost_setVersion(host, HTTP_09);
1.80      frystyk   586:        return status;
                    587:     } else {
1.140     frystyk   588:        HTResponse * response = HTRequest_response(request);
1.133     frystyk   589:        char *ptr = me->buffer+4;                      /* Skip the HTTP part */
1.81      frystyk   590:        me->version = HTNextField(&ptr);
1.95      frystyk   591: 
1.130     frystyk   592:        /* Here we want to find out when to use persistent connection */
1.133     frystyk   593:        if (!strncasecomp(me->version, "/1.0", 4)) {
1.128     frystyk   594:            if (PROT_TRACE)HTTrace("HTTP Status. This is a HTTP/1.0 server\n");
                    595:            HTHost_setVersion(host, HTTP_10);
1.133     frystyk   596:        } else if (!strncasecomp(me->version, "/1.", 3)) {     /* 1.x family */
1.128     frystyk   597:            HTHost_setVersion(host, HTTP_11);
1.141     frystyk   598: #ifdef HT_MUX
                    599:            HTNet_setPersistent(net, YES, HT_TP_INTERLEAVE);
                    600: #else
1.147     frystyk   601:            if (ConnectionMode & HTTP_NO_PIPELINING) {
                    602:                if (PROT_TRACE) HTTrace("HTTP........ Mode is HTTP/1.1 WITH NO PIPELINING\n");
                    603:                HTNet_setPersistent(net, YES, HT_TP_SINGLE);
                    604:            } else if (ConnectionMode & HTTP_FORCE_10) {
                    605:                if (PROT_TRACE) HTTrace("HTTP........ Mode is FORCE HTTP/1.0\n");
                    606:                HTHost_setVersion(host, HTTP_10);
                    607:                HTNet_setPersistent(net, NO, HT_TP_SINGLE);
                    608:            } else
                    609:                HTNet_setPersistent(net, YES, HT_TP_PIPELINE);
1.145     frystyk   610: #endif /* HT_MUX */
1.133     frystyk   611:        } else { 
                    612:            if (PROT_TRACE)HTTrace("HTTP Status. No 1.x version number - treat it as a HTTP/1.0 server\n");
                    613:            HTHost_setVersion(host, HTTP_10);
1.128     frystyk   614:        }
1.95      frystyk   615: 
1.81      frystyk   616:        me->status = atoi(HTNextField(&ptr));
1.133     frystyk   617:        /* Kludge to fix the NCSA server version bug */
                    618:        if (me->status == 0) me->status = atoi(me->version);
                    619: 
1.81      frystyk   620:        me->reason = ptr;
                    621:        if ((ptr = strchr(me->reason, '\r')) != NULL)     /* Strip \r and \n */
                    622:            *ptr = '\0';
                    623:        else if ((ptr = strchr(me->reason, '\n')) != NULL)
                    624:            *ptr = '\0';
                    625: 
1.130     frystyk   626:        /* 
                    627:        **  If it is a 1xx code then find out what to do and return until we
                    628:        **  get the next code. In the case of Upgrade we may not get back here
                    629:        **  at all. If we are uploading an entity then continue doing that
                    630:        */
                    631:        if (me->status/100 == 1) {
1.136     frystyk   632:            if (HTTPInformation(me) == YES) {
                    633:                me->buflen = 0;
                    634:                me->state = EOL_BEGIN;
1.150     frystyk   635:                me->target = HTStreamStack(WWW_MIME_CONT,
                    636:                                           HTRequest_debugFormat(request),
                    637:                                           HTRequest_debugStream(request),
                    638:                                           request, NO);
1.136     frystyk   639:                return HTMethod_hasEntity(HTRequest_method(request)) ?
                    640:                    HT_CONTINUE : HT_OK;
1.103     frystyk   641:            }
1.56      frystyk   642:        }
1.133     frystyk   643: 
                    644:        /*
                    645:        **  As we are getting fresh metainformation in the HTTP response,
                    646:        **  we clear the old metainfomation in order not to mix it with the new
                    647:        **  one. This is particularly important for the content-length and the
1.139     frystyk   648:        **  like. The TRACE and OPTIONS method just adds to the current 
                    649:        **  metainformation so in that case we don't clear the anchor.
1.133     frystyk   650:        */
1.136     frystyk   651:        if (me->status==200 || me->status==203 || me->status==300) {
1.140     frystyk   652:            /*
                    653:            **  200, 203 and 300 are all fully cacheable responses. No byte 
                    654:            **  ranges or anything else make life hard in this case.
                    655:            */
1.148     frystyk   656:            HTAnchor_clearHeader(HTRequest_anchor(request));
1.140     frystyk   657:            HTResponse_setCachable(response, YES);
1.136     frystyk   658:            me->target = HTStreamStack(WWW_MIME,
                    659:                                       HTRequest_outputFormat(request),
                    660:                                       HTRequest_outputStream(request),
                    661:                                       request, NO);
1.140     frystyk   662:        } else if (me->status==206) {
                    663:            /*
                    664:            **  We got a partial response and now we must check whether
                    665:            **  we issued a cache If-Range request or it was a new 
                    666:            **  partial response which we don't have in cache. In the latter
                    667:            **  case, we don't cache the object and in the former we append
                    668:            **  the result to the already existing cache entry.
                    669:            */
                    670:            HTReload reload = HTRequest_reloadMode(request);
                    671:            if (reload == HT_CACHE_RANGE_VALIDATE) {
                    672:                HTResponse_setCachable(response, YES);
                    673:                me->target = HTStreamStack(WWW_MIME_PART,
                    674:                                           HTRequest_outputFormat(request),
                    675:                                           HTRequest_outputStream(request),
                    676:                                           request, NO);
                    677:            } else {
1.149     frystyk   678:                HTAnchor_clearHeader(HTRequest_anchor(request));
1.140     frystyk   679:                me->target = HTStreamStack(WWW_MIME,
                    680:                                           HTRequest_outputFormat(request),
                    681:                                           HTRequest_outputStream(request),
                    682:                                           request, NO);
                    683:            }
1.139     frystyk   684:        } else if (me->status==204 || me->status==304) {
1.140     frystyk   685:            HTResponse_setCachable(response, YES);
1.136     frystyk   686:            me->target = HTStreamStack(WWW_MIME_HEAD,
                    687:                                       HTRequest_debugFormat(request),
                    688:                                       HTRequest_debugStream(request),
                    689:                                       request, NO);
                    690:        } else if (HTRequest_debugStream(request)) {
                    691:            me->target = HTStreamStack(WWW_MIME,
                    692:                                       HTRequest_debugFormat(request),
                    693:                                       HTRequest_debugStream(request),
                    694:                                       request, NO);
                    695:        } else {
1.140     frystyk   696:            /*
                    697:            **  We still need to parse the MIME part in order to find any
                    698:            **  valuable meta information which is needed from the response.
                    699:            */
1.136     frystyk   700:            me->target = HTStreamStack(WWW_MIME,
                    701:                                       HTRequest_debugFormat(request),
                    702:                                       HTRequest_debugStream(request),
                    703:                                       request, NO);
1.133     frystyk   704:        }
1.56      frystyk   705:     }
1.113     frystyk   706:     if (!me->target) me->target = HTErrorStream();
1.81      frystyk   707:     HTTPNextState(me);                                    /* Get next state */
1.80      frystyk   708:     me->transparent = YES;
                    709:     return HT_OK;
1.71      frystyk   710: }
1.56      frystyk   711: 
1.80      frystyk   712: /*
                    713: **     Searches for HTTP header line until buffer fills up or a CRLF or LF
                    714: **     is found
                    715: */
1.119     frystyk   716: PRIVATE int HTTPStatus_put_block (HTStream * me, const char * b, int l)
1.71      frystyk   717: {
1.150     frystyk   718:     int status = HT_OK;
1.153   ! frystyk   719:     int length = l;
1.146     frystyk   720:     me->startLen = me->buflen;
1.80      frystyk   721:     while (!me->transparent && l-- > 0) {
                    722:        if (me->target) {
1.150     frystyk   723:            if (me->cont) {
                    724:                FREE_TARGET;
                    725:                me->target = NULL;
                    726:                l++;
                    727:            } else {
                    728:                if ((status = stream_pipe(me)) == HT_CONTINUE) {
                    729:                    b++; break;
                    730:                }
                    731:                if (status != HT_OK) return status;
                    732:            }
1.80      frystyk   733:        } else {
                    734:            *(me->buffer+me->buflen++) = *b;
                    735:            if (me->state == EOL_FCR) {
                    736:                if (*b == LF) { /* Line found */
1.150     frystyk   737:                    if ((status = stream_pipe(me)) == HT_CONTINUE) {
                    738:                        me->cont = YES;
                    739:                        b++; break;
                    740:                    }
                    741:                    if (status != HT_OK) return status;
1.80      frystyk   742:                } else {
                    743:                    me->state = EOL_BEGIN;
                    744:                }
                    745:            } else if (*b == CR) {
                    746:                me->state = EOL_FCR;
                    747:            } else if (*b == LF) {
1.150     frystyk   748:                if ((status = stream_pipe(me)) == HT_CONTINUE) {
                    749:                    me->cont = YES;
                    750:                    b++; break;
                    751:                }
                    752:                if (status != HT_OK) return status;
1.71      frystyk   753:            } else {
1.80      frystyk   754:                if (me->buflen >= MAX_STATUS_LEN) {
1.150     frystyk   755:                    if ((status = stream_pipe(me)) == HT_CONTINUE) {
                    756:                        me->cont = YES;
                    757:                        b++; break;
                    758:                    }
                    759:                    if (status != HT_OK) return status;
1.80      frystyk   760:                }
1.71      frystyk   761:            }
1.80      frystyk   762:            b++;
1.71      frystyk   763:        }
1.56      frystyk   764:     }
1.153   ! frystyk   765: 
        !           766:     if (length != l)
        !           767:        HTHost_setConsumed(HTNet_host(HTRequest_net(me->request)), length - l);
        !           768: 
1.99      frystyk   769:     if (l > 0) return PUTBLOCK(b, l);
1.150     frystyk   770:     return status;
1.56      frystyk   771: }
                    772: 
1.119     frystyk   773: PRIVATE int HTTPStatus_put_string (HTStream * me, const char * s)
1.71      frystyk   774: {
1.80      frystyk   775:     return HTTPStatus_put_block(me, s, (int) strlen(s));
1.71      frystyk   776: }
1.56      frystyk   777: 
1.100     frystyk   778: PRIVATE int HTTPStatus_put_character (HTStream * me, char c)
1.71      frystyk   779: {
1.80      frystyk   780:     return HTTPStatus_put_block(me, &c, 1);
                    781: }
                    782: 
1.100     frystyk   783: PRIVATE int HTTPStatus_flush (HTStream * me)
1.80      frystyk   784: {
                    785:     return (*me->target->isa->flush)(me->target);
1.71      frystyk   786: }
                    787: 
1.100     frystyk   788: PRIVATE int HTTPStatus_free (HTStream * me)
1.71      frystyk   789: {
1.87      frystyk   790:     int status = HT_OK;
                    791:     if (me->target) {
                    792:        if ((status = (*me->target->isa->_free)(me->target))==HT_WOULD_BLOCK)
                    793:            return HT_WOULD_BLOCK;
                    794:     }
1.115     frystyk   795:     HT_FREE(me);
1.100     frystyk   796:     return status;
1.71      frystyk   797: }
                    798: 
1.104     frystyk   799: PRIVATE int HTTPStatus_abort (HTStream * me, HTList * e)
1.71      frystyk   800: {
                    801:     if (me->target)
1.74      frystyk   802:        ABORT_TARGET;
1.115     frystyk   803:     HT_FREE(me);
1.74      frystyk   804:     if (PROT_TRACE)
1.116     eric      805:        HTTrace("HTTPStatus.. ABORTING...\n");
1.80      frystyk   806:     return HT_ERROR;
1.71      frystyk   807: }
                    808: 
                    809: /*     HTTPStatus Stream
                    810: **     -----------------
                    811: */
1.119     frystyk   812: PRIVATE const HTStreamClass HTTPStatusClass =
1.71      frystyk   813: {              
                    814:     "HTTPStatus",
1.80      frystyk   815:     HTTPStatus_flush,
1.71      frystyk   816:     HTTPStatus_free,
                    817:     HTTPStatus_abort,
                    818:     HTTPStatus_put_character,
                    819:     HTTPStatus_put_string,
                    820:     HTTPStatus_put_block
                    821: };
                    822: 
1.113     frystyk   823: PUBLIC HTStream * HTTPStatus_new (HTRequest *  request,
                    824:                                  void *        param,
                    825:                                  HTFormat      input_format,
                    826:                                  HTFormat      output_format,
                    827:                                  HTStream *    output_stream)
1.71      frystyk   828: {
1.115     frystyk   829:     HTStream * me;
                    830:     if ((me = (HTStream  *) HT_CALLOC(1, sizeof(HTStream))) == NULL)
                    831:         HT_OUTOFMEM("HTTPStatus_new");
1.71      frystyk   832:     me->isa = &HTTPStatusClass;
1.113     frystyk   833:     if (request) {
1.126     frystyk   834:        HTNet * net = HTRequest_net(request);
1.125     frystyk   835:         /* Get existing copy */
                    836:        http_info * http = (http_info *) HTNet_context(net);
1.113     frystyk   837:        me->request = request;
                    838:        me->http = http;
                    839:        http->next = HTTP_ERROR;
                    840:        me->state = EOL_BEGIN;
                    841:        return me;
                    842:     } else
                    843:        return HTErrorStream();
1.71      frystyk   844: }
                    845: 
                    846: /* ------------------------------------------------------------------------- */
                    847: 
                    848: /*             Load Document from HTTP Server                       HTLoadHTTP
1.55      frystyk   849: **             ==============================
                    850: **
                    851: **     Given a hypertext address, this routine loads a document.
                    852: **
                    853: ** On entry,
                    854: **      request                This is the request structure
1.94      frystyk   855: **     returns         HT_ERROR        Error has occured in call back
                    856: **                     HT_OK           Call back was OK
1.55      frystyk   857: */
1.141     frystyk   858: PRIVATE int HTTPEvent (SOCKET soc, void * pVoid, HTEventType type);
                    859: 
                    860: PUBLIC int HTLoadHTTP (SOCKET soc, HTRequest * request)
1.55      frystyk   861: {
                    862:     http_info *http;                       /* Specific protocol information */
1.112     frystyk   863:     HTParentAnchor *anchor = HTRequest_anchor(request);
1.141     frystyk   864:     HTNet * net = HTRequest_net(request);
1.112     frystyk   865: 
1.94      frystyk   866:     /*
                    867:     ** Initiate a new http structure and bind to request structure
                    868:     ** This is actually state HTTP_BEGIN, but it can't be in the state
                    869:     ** machine as we need the structure first.
                    870:     */
1.141     frystyk   871:     if (PROT_TRACE) HTTrace("HTTP........ Looking for `%s\'\n",
                    872:                            HTAnchor_physical(anchor));
                    873:     if ((http = (http_info *) HT_CALLOC(1, sizeof(http_info))) == NULL)
                    874:       HT_OUTOFMEM("HTLoadHTTP");
                    875:     http->net = net;
                    876:     HTNet_setContext(net, http);
                    877:     HTNet_setEventCallback(net, HTTPEvent);
                    878:     HTNet_setEventParam(net, http);  /* callbacks get http* */
                    879: 
                    880:     return HTTPEvent(soc, http, HTEvent_BEGIN);                /* get it started - ops is ignored */
                    881: }
                    882: 
                    883: PRIVATE int HTTPEvent (SOCKET soc, void * pVoid, HTEventType type)
                    884: {
                    885:     http_info * http = (http_info *)pVoid;
                    886:     int status = HT_ERROR;
                    887:     HTNet * net = http->net;
                    888:     HTRequest * request = HTNet_request(net);
1.144     frystyk   889:     HTParentAnchor * anchor = HTRequest_anchor(request);
                    890:     HTHost * host = HTNet_host(net);
1.141     frystyk   891: 
                    892:     /*
                    893:     **  Check whether we have been interrupted
                    894:     */
                    895:     if (type == HTEvent_BEGIN) {
1.134     frystyk   896:        http->next = HTTP_OK;
                    897:        http->result = HT_ERROR;
1.141     frystyk   898:     } else if (type == HTEvent_CLOSE) {
1.112     frystyk   899:        HTRequest_addError(request, ERR_FATAL, NO, HTERR_INTERRUPTED,
                    900:                           NULL, 0, "HTLoadHTTP");
                    901:        HTTPCleanup(request, HT_INTERRUPTED);
1.94      frystyk   902:        return HT_OK;
1.141     frystyk   903:     } else if (type == HTEvent_END) {
                    904:        HTTPCleanup(request, http->result);
                    905:        return HT_OK;
                    906:     } else if (type == HTEvent_RESET) {
                    907:        HTTPCleanup(request, HT_RECOVER_PIPE);
1.145     frystyk   908:        http->state = HTTP_BEGIN;
1.141     frystyk   909:        return HT_OK;
                    910:     }
                    911: 
1.71      frystyk   912:     /* Now jump into the machine. We know the state from the previous run */
                    913:     while (1) {
                    914:        switch (http->state) {
1.134     frystyk   915:        case HTTP_BEGIN:
1.144     frystyk   916:            status = HTHost_connect(host, net, HTAnchor_physical(anchor), HTTP_PORT);
                    917:            host = HTNet_host(net);
1.153   ! frystyk   918:             if (status == HT_OK) {
1.140     frystyk   919: 
1.123     frystyk   920:                /*
1.140     frystyk   921:                **  Check the protocol class to see if we have connected to a
                    922:                **  the right class of server, in this case HTTP. If we don't 
                    923:                **  know the server then assume a HTTP/1.0
1.123     frystyk   924:                */
                    925:                {
                    926:                    char * s_class = HTHost_class(host);
1.140     frystyk   927:                    if (!s_class) {
                    928:                        if (HTRequest_proxy(request) == NULL)
                    929:                            HTRequest_addConnection(request, "Keep-Alive", "");
                    930:                        HTHost_setClass(host, "http");
                    931:                    } else if (strcasecomp(s_class, "http")) {
1.123     frystyk   932:                        HTRequest_addError(request, ERR_FATAL, NO, HTERR_CLASS,
                    933:                                           NULL, 0, "HTLoadHTTP");
                    934:                        http->state = HTTP_ERROR;
                    935:                        break;
                    936:                    }
1.95      frystyk   937:                }
1.147     frystyk   938: 
                    939:                if (ConnectionMode & HTTP_NO_PIPELINING) {
                    940:                    if (PROT_TRACE) HTTrace("HTTP........ Mode is HTTP/1.1 WITH NO PIPELINING\n");
                    941:                    HTRequest_setFlush(request, YES);
                    942:                } else if (ConnectionMode & HTTP_FORCE_10) {
                    943:                    if (PROT_TRACE) HTTrace("HTTP........ Mode is FORCE HTTP/1.0\n");
                    944:                    HTHost_setVersion(host, HTTP_10);
                    945:                }
                    946: 
1.151     frystyk   947:                if (HTNet_preemptive(net)) {
                    948:                    if (PROT_TRACE) HTTrace("HTTP........ Force flush on preemptive load\n");
                    949:                    HTRequest_setFlush(request, YES);
                    950:                }
                    951: 
1.147     frystyk   952:                /* Jump to next state */
1.144     frystyk   953:                http->state = HTTP_NEED_STREAM;
                    954:            } else if (status == HT_WOULD_BLOCK || status == HT_PENDING)
                    955:                return HT_OK;
                    956:            else        
                    957:                http->state = HTTP_ERROR;              /* Error or interrupt */
                    958:            break;
                    959:            
                    960:        case HTTP_NEED_STREAM:
1.138     frystyk   961: 
1.144     frystyk   962:            /* 
                    963:            ** Create the stream pipe FROM the channel to the application.
                    964:            ** The target for the input stream pipe is set up using the
                    965:            ** stream stack.
                    966:            */
1.153   ! frystyk   967:             {
1.144     frystyk   968:                HTStream *me=HTStreamStack(WWW_HTTP,
                    969:                                           HTRequest_outputFormat(request),
                    970:                                           HTRequest_outputStream(request),
                    971:                                           request, YES);
                    972:                HTNet_setReadStream(net, me);
                    973:                HTRequest_setOutputConnected(request, YES);
                    974:            }
1.127     frystyk   975: 
1.144     frystyk   976:            /*
                    977:            ** Create the stream pipe TO the channel from the application
                    978:            ** and hook it up to the request object
                    979:            */
                    980:            {
                    981:                HTChannel * channel = HTHost_channel(host);
                    982:                HTOutputStream * output = HTChannel_getChannelOStream(channel);
                    983:                int version = HTHost_version(host);
                    984:                HTStream * app = NULL;
                    985:                
1.123     frystyk   986:                /*
1.144     frystyk   987:                **  Instead of calling this directly we could have a 
                    988:                **  stream stack builder on the output stream as well
1.123     frystyk   989:                */
1.141     frystyk   990: #ifdef HT_MUX
1.144     frystyk   991:                output = (HTOutputStream *)
                    992:                    HTBuffer_new(HTMuxWriter_new(host, net, output), request, 512);
1.141     frystyk   993: #endif
                    994:                    
1.139     frystyk   995: #ifdef HTTP_DUMP
1.144     frystyk   996:                if (PROT_TRACE) {
1.147     frystyk   997:                    FILE * htfp = NULL;
                    998:                    if ((htfp = fopen(HTTP_OUTPUT, "ab")) != NULL) {
1.144     frystyk   999:                        output = (HTOutputStream *)
1.147     frystyk  1000:                            HTTee((HTStream *) output, HTFWriter_new(request, htfp, NO), NULL);
                   1001:                        HTTrace("HTTP........ Dumping request to `%s\'\n", HTTP_OUTPUT);
1.144     frystyk  1002:                    }
                   1003:                }       
1.139     frystyk  1004: #endif /* HTTP_DUMP */
1.144     frystyk  1005:                app = HTMethod_hasEntity(HTRequest_method(request)) ?
                   1006:                    HTMIMERequest_new(request,
                   1007:                                      HTTPRequest_new(request, (HTStream *) output, NO,
                   1008:                                                      version),
                   1009:                                      YES) :
                   1010:                    HTTPRequest_new(request, (HTStream *) output, YES, version);
                   1011:                HTRequest_setInputStream(request, app);
                   1012:            }
1.88      frystyk  1013: 
1.144     frystyk  1014:            /*
                   1015:            ** Set up concurrent read/write if this request isn't the
                   1016:            ** source for a PUT or POST. As source we don't start reading
                   1017:            ** before all destinations are ready. If destination then
                   1018:            ** register the input stream and get ready for read
                   1019:            */
                   1020:            if (HTRequest_isDestination(request)) {
                   1021:                HTHost_register(host, net, HTEvent_READ);
                   1022:                HTRequest_linkDestination(request);
                   1023:            }
                   1024:            http->state = HTTP_CONNECTED;
                   1025:            type = HTEvent_WRITE;                           /* fresh, so try a write */
1.71      frystyk  1026:            break;
                   1027: 
1.87      frystyk  1028:            /* As we can do simultanous read and write this is now one state */
1.141     frystyk  1029:          case HTTP_CONNECTED:
                   1030:              if (type == HTEvent_WRITE) {
                   1031:                 if (HTRequest_isDestination(request)) {
                   1032:                     HTRequest * source = HTRequest_source(request);
                   1033:                     HTNet * srcnet = HTRequest_net(source);
                   1034:                     if (srcnet) {
1.149     frystyk  1035:                         HTHost_register(HTNet_host(srcnet), srcnet, HTEvent_READ);
                   1036:                         HTHost_unregister(HTNet_host(srcnet), srcnet, HTEvent_WRITE);
1.141     frystyk  1037:                     }
                   1038:                     return HT_OK;
                   1039:                 }
1.126     frystyk  1040: 
                   1041:                /*
                   1042:                **  Should we use the input stream directly or call the post
                   1043:                **  callback function to send data down to the network?
                   1044:                */
                   1045:                {
                   1046:                    HTStream * input = HTRequest_inputStream(request);
                   1047:                    HTPostCallback * pcbf = HTRequest_postCallback(request);
1.131     frystyk  1048:                    if (pcbf) {
1.139     frystyk  1049:                        if (http->lock)
                   1050:                            return HT_OK;
                   1051:                        else {
1.141     frystyk  1052:                            status = (*pcbf)(request, input);
1.140     frystyk  1053:                            if (status == HT_PAUSE || status == HT_LOADED) {
1.141     frystyk  1054:                                type = HTEvent_READ;
1.139     frystyk  1055:                                http->lock = YES;
1.141     frystyk  1056:                            } else if (status==HT_CLOSED)
                   1057:                                http->state = HTTP_RECOVER_PIPE;
                   1058:                            else if (status == HT_ERROR) {
1.139     frystyk  1059:                                http->result = HT_INTERRUPTED;
                   1060:                                http->state = HTTP_ERROR;
                   1061:                                break;
                   1062:                            }
                   1063:                        }
1.131     frystyk  1064:                    } else {
1.142     frystyk  1065:                        /*
                   1066:                        **  Check to see if we can start a new request
                   1067:                        **  pending in the host object.
                   1068:                        */
1.144     frystyk  1069:                        HTHost_launchPending(host);
1.142     frystyk  1070:                        status = HTRequest_flush(request) ?
1.144     frystyk  1071:                            HTHost_forceFlush(host) : (*input->isa->flush)(input);
1.141     frystyk  1072:                        type = HTEvent_READ;
1.131     frystyk  1073:                    }
                   1074:                    if (status == HT_WOULD_BLOCK) return HT_OK;
1.126     frystyk  1075:                }
1.141     frystyk  1076:            } else if (type == HTEvent_FLUSH) {
                   1077:                HTStream * input = HTRequest_inputStream(request);
                   1078:                if (input == NULL)
                   1079:                    return HT_ERROR;
                   1080:                return (*input->isa->flush)(input);
                   1081:            } else if (type == HTEvent_READ) {
1.144     frystyk  1082:                status = HTHost_read(host, net);
1.131     frystyk  1083:                if (status == HT_WOULD_BLOCK)
1.94      frystyk  1084:                    return HT_OK;
1.131     frystyk  1085:                else if (status == HT_CONTINUE) {
1.130     frystyk  1086:                    if (PROT_TRACE) HTTrace("HTTP........ Continuing\n");
1.139     frystyk  1087:                    http->lock = NO;
1.141     frystyk  1088:                    type = HTEvent_WRITE;
1.130     frystyk  1089:                    continue;
1.133     frystyk  1090:                } else if (status==HT_LOADED)
1.141     frystyk  1091:                    http->state = http->next;   /* Jump to next state (OK or ERROR) */
                   1092:                else if (status==HT_CLOSED)
                   1093:                    http->state = HTTP_RECOVER_PIPE;
                   1094:                else
1.94      frystyk  1095:                    http->state = HTTP_ERROR;
1.90      frystyk  1096:            } else {
1.141     frystyk  1097:                http->state = HTTP_ERROR;       /* don't know how to handle OOB */
1.90      frystyk  1098:            }
1.71      frystyk  1099:            break;
1.141     frystyk  1100: 
1.134     frystyk  1101:          case HTTP_OK:
1.88      frystyk  1102:            if (HTRequest_isPostWeb(request)) {
1.91      frystyk  1103:                if (HTRequest_isDestination(request)) {
1.126     frystyk  1104:                    HTRequest * source = HTRequest_source(request);
1.91      frystyk  1105:                    HTLink *link =
1.127     frystyk  1106:                        HTLink_find((HTAnchor *)HTRequest_anchor(source),
1.112     frystyk  1107:                                          (HTAnchor *) anchor);
1.109     frystyk  1108:                    HTLink_setResult(link, HT_LINK_OK);
1.91      frystyk  1109:                }
1.112     frystyk  1110:            }
1.134     frystyk  1111:            HTTPCleanup(request, http->result);
1.94      frystyk  1112:            return HT_OK;
1.71      frystyk  1113:            break;
1.141     frystyk  1114: 
                   1115:           case HTTP_RECOVER_PIPE:
                   1116:          {
                   1117:              /*
                   1118:              ** If this is a persistent connection and we get a close
                   1119:              ** then it is an error and we should recover from it by
                   1120:              ** restarting the pipe line of requests if any
                   1121:              */
1.151     frystyk  1122:              if (HTHost_isPersistent(host) && !HTHost_closeNotification(host)) {
1.143     frystyk  1123:                  if (host == NULL) return HT_ERROR;
1.144     frystyk  1124:                  HTRequest_setFlush(request, YES);
                   1125:                  HTHost_recoverPipe(host);
                   1126:                  http->state = HTTP_BEGIN;
                   1127:                  HTHost_launchPending(host);
                   1128:                  return HT_OK;
1.141     frystyk  1129:              } else
                   1130:                  http->state = HTTP_OK;
                   1131:          }
1.143     frystyk  1132:          break;
1.141     frystyk  1133: 
1.71      frystyk  1134:          case HTTP_ERROR:
1.143     frystyk  1135:              if (HTRequest_isPostWeb(request)) {
                   1136:                  if (HTRequest_isDestination(request)) {
                   1137:                      HTRequest * source = HTRequest_source(request);
                   1138:                      HTLink *link =
                   1139:                          HTLink_find((HTAnchor *)HTRequest_anchor(source),
                   1140:                                      (HTAnchor *) anchor);
                   1141:                      HTLink_setResult(link, HT_LINK_ERROR);
                   1142:                  }
                   1143:                  HTRequest_killPostWeb(request);
                   1144:              }
                   1145:              HTTPCleanup(request, http->result);
                   1146:              return HT_OK;
                   1147:              break;
                   1148: 
1.141     frystyk  1149:        default:
                   1150:            HTTrace("bad http state %d.\n", http->state);
                   1151:            HTDebugBreak();
1.71      frystyk  1152:        }
                   1153:     } /* End of while(1) */
                   1154: }    
1.88      frystyk  1155: 
1.147     frystyk  1156: PUBLIC void HTTP_setConnectionMode (HTTPConnectionMode mode)
                   1157: {
                   1158:     ConnectionMode = mode;
                   1159: }
                   1160: 
                   1161: PUBLIC HTTPConnectionMode HTTP_connectionMode (void)
                   1162: {
                   1163:     return ConnectionMode;
                   1164: }
1.21      luotonen 1165: 

Webmaster