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

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

Webmaster