Annotation of libwww/Library/src/HTTPServ.c, revision 2.23

2.1       frystyk     1: /*                                                                 HTTPServ.c
                      2: **     HTTP SERVER MODULE
                      3: **
                      4: **     (c) COPYRIGHT MIT 1995.
                      5: **     Please first read the full copyright statement in the file COPYRIGH.
2.23    ! frystyk     6: **     @(#) $Id: HTTPServ.c,v 2.22.2.4 1996/11/08 19:49:54 eric Exp $
2.1       frystyk     7: **
                      8: **     This module implments the HTTP protocol as a state machine
                      9: **
                     10: ** History:
                     11: **     Dec 95 HFN      Written with Christmas in my eyes
                     12: **
                     13: */
                     14: 
                     15: /* Library include files */
2.14      frystyk    16: #include "sysdep.h"
2.16      frystyk    17: #include "WWWUtil.h"
                     18: #include "WWWCore.h"
                     19: #include "WWWMIME.h"
                     20: #include "WWWStream.h"
2.18      frystyk    21: #include "WWWTrans.h"
2.1       frystyk    22: #include "HTNetMan.h"
                     23: #include "HTTPUtil.h"
2.2       frystyk    24: #include "HTTPRes.h"
2.1       frystyk    25: #include "HTTPServ.h"                                         /* Implements */
                     26: 
                     27: /* Macros and other defines */
                     28: #define PUTC(c)                (*me->target->isa->put_character)(me->target, c)
                     29: #define PUTS(s)                (*me->target->isa->put_string)(me->target, s)
                     30: #define PUTBLOCK(b, l) (*me->target->isa->put_block)(me->target, b, l)
                     31: 
                     32: /* Final states have negative value */
                     33: typedef enum _HTTPState {
2.6       frystyk    34:     HTTPS_ERROR                = -2,
                     35:     HTTPS_OK           = -1,
2.1       frystyk    36:     HTTPS_BEGIN                = 0,
2.18      frystyk    37:     HTTPS_NEED_REQUEST,
                     38:     HTTPS_LOAD_CLIENT
2.1       frystyk    39: } HTTPState;
                     40: 
                     41: /* This is the context object for the this module */
                     42: typedef struct _https_info {
2.18      frystyk    43:     HTRequest *        server;                                /* The server request */
                     44:     HTList *   clients;                          /* List of client requests */
2.1       frystyk    45:     HTTPState  state;                    /* Current State of the connection */
2.23    ! frystyk    46:     HTNet *    net;
2.1       frystyk    47: } https_info;
                     48: 
                     49: /* The HTTP Receive Stream */
                     50: struct _HTStream {
2.14      frystyk    51:     const HTStreamClass *      isa;
2.1       frystyk    52:     HTStream *                 target;
                     53:     HTRequest *                        request;
2.9       frystyk    54:     https_info *               http;
2.15      frystyk    55:     HTEOLState                 state;
2.1       frystyk    56:     HTChunk *                  buffer;
                     57:     BOOL                       transparent;
                     58: };
                     59: 
2.16      frystyk    60: struct _HTInputStream {
                     61:     const HTInputStreamClass * isa;
                     62: };
                     63: 
2.1       frystyk    64: /* ------------------------------------------------------------------------- */
2.8       frystyk    65: 
                     66: /*     ServerCleanup
                     67: **     -------------
                     68: **      This function cleans up after the request
                     69: **      Returns YES on OK, else NO
                     70: */
                     71: PRIVATE int ServerCleanup (HTRequest * req, HTNet * net, int status)
                     72: {
2.18      frystyk    73:     https_info * http = (https_info *) HTNet_context(net);
                     74:     HTStream * input = HTRequest_inputStream(req);
                     75:     HTChannel * channel = HTNet_channel(net);
2.8       frystyk    76: 
                     77:     /* Free stream with data TO network */
2.18      frystyk    78:     if (input) {
2.8       frystyk    79:        if (status == HT_INTERRUPTED)
2.18      frystyk    80:            (*input->isa->abort)(input, NULL);
2.8       frystyk    81:        else
2.18      frystyk    82:            (*input->isa->_free)(input);
                     83:        HTRequest_setInputStream(req, NULL);
2.8       frystyk    84:     }
                     85: 
2.18      frystyk    86:     /* Kill all remaining requests */
                     87:     if (http->clients) {
                     88:        HTList * cur = http->clients;
                     89:        HTRequest * pres;
                     90:        while ((pres = HTList_nextObject(cur)) != NULL)
                     91:            HTRequest_kill(pres);
                     92:        HTList_delete(http->clients);
                     93:     }
                     94: 
                     95:     /*
                     96:     **  Remove the net object and our own context structure for http.
                     97:     ** Also unregister all pending requests and close the connection
                     98:     */
                     99:     HTChannel_setSemaphore(channel, 0);
                    100:     HTNet_delete(net, HT_IGNORE);
                    101: 
2.11      frystyk   102:     HT_FREE(http);
2.8       frystyk   103:     return YES;
                    104: }
                    105: 
                    106: /* ------------------------------------------------------------------------- */
2.6       frystyk   107: /*                             REPLY STREAM                                 */
                    108: /* ------------------------------------------------------------------------- */
2.1       frystyk   109: 
2.6       frystyk   110: /*
                    111: **     This is our handle to the server reply stream when data is coming
2.9       frystyk   112: **     back from our "client" request. It is responsible for setting up the
                    113: **     remaining streams in order to produce a complete HTTP output.
                    114: **     If we have a HTTP 1.x response then forward untouched.
2.6       frystyk   115: */
2.18      frystyk   116: PRIVATE int MakeReplyPipe (HTStream * me, HTRequest * client)
2.9       frystyk   117: {
                    118:     char * response_line = NULL;
                    119: 
                    120:     /* Generate the Response line */
                    121:     {
                    122:        HTAlertCallback *cbf = HTAlert_find(HT_A_MESSAGE);
                    123:        if (cbf) {
                    124:            HTAlertPar * reply = HTAlert_newReply();
                    125:            if ((*cbf)(client, HT_A_MESSAGE, HT_MSG_NULL, NULL,
2.18      frystyk   126:                       HTRequest_error(client), reply))
2.9       frystyk   127:                response_line = HTAlert_replyMessage(reply);
                    128:            HTAlert_deleteReply(reply);
                    129:        }
2.20      frystyk   130: 
2.9       frystyk   131:        if (response_line) {
                    132:            PUTS(response_line);
2.11      frystyk   133:            HT_FREE(response_line);
2.9       frystyk   134:        } else {        
2.18      frystyk   135:            PUTS(HTTP_VERSION);
                    136:            PUTS(" 500 Internal");
2.9       frystyk   137:            PUTC(CR);
                    138:            PUTC(LF);
                    139:        }
                    140:     }
                    141: 
                    142:     /*
2.19      frystyk   143:     ** We now have to create the rest of the response stream. We see whether
                    144:     ** there is a data object or not by looking at the Content Type of the
                    145:     ** client anchor.
2.9       frystyk   146:     */
2.19      frystyk   147:     {
                    148:        HTParentAnchor * anchor = HTRequest_anchor(client);
                    149:        HTFormat format = HTAnchor_format(anchor);
                    150:        me->target = (format == WWW_UNKNOWN) ?
2.22      frystyk   151:            HTTPResponse_new(client, me->target, YES, HTTP_11) :
2.19      frystyk   152:            HTMIMERequest_new(client,
2.22      frystyk   153:                HTTPResponse_new(client,me->target, NO, HTTP_11), YES);
2.19      frystyk   154:     }
2.18      frystyk   155:     return HT_OK;
2.9       frystyk   156: }
2.6       frystyk   157: 
2.14      frystyk   158: PRIVATE int HTTPReply_put_block (HTStream * me, const char * b, int l)
2.1       frystyk   159: {
2.9       frystyk   160:     if (me->transparent)
                    161:        return b ? PUTBLOCK(b, l) : HT_OK;
                    162:     else {
2.18      frystyk   163:        MakeReplyPipe(me, me->request);
                    164:        me->transparent = YES;
2.9       frystyk   165:        return b ? PUTBLOCK(b, l) : HT_OK;
                    166:     }
2.6       frystyk   167: }
                    168: 
2.14      frystyk   169: PRIVATE int HTTPReply_put_string (HTStream * me, const char * s)
2.6       frystyk   170: {
2.9       frystyk   171:     return HTTPReply_put_block(me, s, strlen(s));
2.6       frystyk   172: }
                    173: 
                    174: PRIVATE int HTTPReply_put_character (HTStream * me, char c)
                    175: {
2.9       frystyk   176:     return HTTPReply_put_block(me, &c, 1);
2.6       frystyk   177: }
                    178: 
                    179: PRIVATE int HTTPReply_flush (HTStream * me)
                    180: {
2.9       frystyk   181:     int status = HTTPReply_put_block(me, NULL, 0);
                    182:     return status==HT_OK ? (*me->target->isa->flush)(me->target) : status;
2.6       frystyk   183: }
2.1       frystyk   184: 
2.6       frystyk   185: PRIVATE int HTTPReply_free (HTStream * me)
                    186: {
2.18      frystyk   187:     int status = HTTPReply_put_block(me, NULL, 0);
2.12      eric      188:     if (STREAM_TRACE) HTTrace("HTTPReply... Freeing server stream\n");
2.18      frystyk   189:     return status==HT_OK ? (*me->target->isa->_free)(me->target) : status;
2.6       frystyk   190: }
                    191: 
                    192: PRIVATE int HTTPReply_abort (HTStream * me, HTList * e)
                    193: {
2.12      eric      194:     if (STREAM_TRACE) HTTrace("HTTPReply... ABORTING\n");
2.18      frystyk   195:     if (me->target) (*me->target->isa->abort)(me->target, e);
2.11      frystyk   196:     HT_FREE(me);
2.6       frystyk   197:     return HT_ERROR;
                    198: }
                    199: 
                    200: /*     HTTPReply Stream
                    201: **     -----------------
                    202: */
2.14      frystyk   203: PRIVATE const HTStreamClass HTTPReplyClass =
2.6       frystyk   204: {              
                    205:     "HTTPReply",
                    206:     HTTPReply_flush,
                    207:     HTTPReply_free,
                    208:     HTTPReply_abort,
                    209:     HTTPReply_put_character,
                    210:     HTTPReply_put_string,
                    211:     HTTPReply_put_block
                    212: };
2.1       frystyk   213: 
2.18      frystyk   214: PRIVATE HTStream * HTTPReply_new (HTRequest * request, https_info * http,
2.9       frystyk   215:                                  HTStream * target)
2.6       frystyk   216: {
2.11      frystyk   217:     HTStream * me;
                    218:     if ((me = (HTStream  *) HT_CALLOC(1, sizeof(HTStream))) == NULL)
                    219:         HT_OUTOFMEM("HTTPReply_new");
2.6       frystyk   220:     me->isa = &HTTPReplyClass;
2.18      frystyk   221:     me->request = request;
                    222:     me->http = http;
2.6       frystyk   223:     me->target = target;
2.18      frystyk   224:     if (STREAM_TRACE) HTTrace("HTTP Reply.. Stream %p created\n", me);
2.6       frystyk   225:     return me;
2.1       frystyk   226: }
                    227: 
2.6       frystyk   228: /* ------------------------------------------------------------------------- */
                    229: /*                             RECEIVE STREAM                               */
                    230: /* ------------------------------------------------------------------------- */
                    231: 
2.1       frystyk   232: /*
                    233: **     Scan the request line for METHOD, URI and VERSION
                    234: **     Returns:        HT_OK           if 1.x request and OK
                    235: **                     HT_LOADED       if 0.9 request and OK
                    236: **                     HT_ERROR        if invalid request line
                    237: */
                    238: PRIVATE int ParseRequest (HTStream * me)
                    239: {
2.18      frystyk   240:     HTRequest * client = HTList_firstObject(me->http->clients);
2.2       frystyk   241:     char * line = HTChunk_data(me->buffer);
2.6       frystyk   242:     char * method_str = HTNextField(&line);
                    243:     char * request_uri = HTNextField(&line);
                    244:     char * version_str = HTNextField(&line);
2.18      frystyk   245:     HTMethod method;
2.6       frystyk   246: 
                    247:     /* Check if method is allowed */
2.18      frystyk   248:     if (!method_str || (method = HTMethod_enum(method_str))==METHOD_INVALID) {
                    249:        HTRequest_addError(client, ERR_FATAL, NO, HTERR_NOT_ALLOWED,
2.6       frystyk   250:                           NULL, 0, "ParseRequest");
                    251:        return HT_ERROR;
                    252:     }
2.18      frystyk   253:     HTRequest_setMethod(client, method);
2.2       frystyk   254: 
2.6       frystyk   255:     /* Find an anchor for the request URI */
                    256:     if (request_uri) {
                    257:        char * uri = HTParse(request_uri, "file:", PARSE_ALL);
2.18      frystyk   258:        HTRequest_setAnchor(client, HTAnchor_findAddress(uri));
2.11      frystyk   259:        HT_FREE(uri);
2.1       frystyk   260:     } else {
2.18      frystyk   261:        HTRequest_addError(client, ERR_FATAL, NO, HTERR_BAD_REQUEST,
2.1       frystyk   262:                           NULL, 0, "ParseRequest");
                    263:        return HT_ERROR;
                    264:     }
                    265: 
2.6       frystyk   266:     /* Get ready to get the rest of the request */
                    267:     if (version_str) {
2.18      frystyk   268:        me->target = HTStreamStack(WWW_MIME_HEAD,
                    269:                                   HTRequest_debugFormat(client),
                    270:                                   HTRequest_debugStream(client),
                    271:                                   client, NO);
2.1       frystyk   272:        return HT_OK;
2.2       frystyk   273:     } else {
2.18      frystyk   274:        HTRequest_addError(client, ERR_FATAL, NO, HTERR_BAD_VERSION,
                    275:                           NULL, 0, "ParseRequest");
                    276:        return HT_ERROR;
2.1       frystyk   277:     }
                    278: }
                    279: 
                    280: /*
                    281: **     Searches for HTTP Request Line before going into transparent mode
                    282: */
2.14      frystyk   283: PRIVATE int HTTPReceive_put_block (HTStream * me, const char * b, int l)
2.1       frystyk   284: {
2.6       frystyk   285:     if (!me->transparent) {
2.14      frystyk   286:        const char *p=b;
2.6       frystyk   287:        while (l>0 && *p!=CR && *p!=LF) l--, p++;
                    288:        HTChunk_putb(me->buffer, b, p-b);
                    289:        if (*p==CR || *p==LF) {
                    290:            int status = ParseRequest(me);
                    291:            HTChunk_clear(me->buffer);
                    292:            if (status != HT_OK) return status;
                    293:            me->transparent = YES;
                    294:            b=p;
                    295:        }
                    296:     }
                    297:     if (l > 0) {
                    298:        int status = PUTBLOCK(b, l);
                    299:        if (status == HT_LOADED) me->transparent = NO;
                    300:        return status;
2.1       frystyk   301:     }
                    302:     return HT_OK;
                    303: }
                    304: 
2.14      frystyk   305: PRIVATE int HTTPReceive_put_string (HTStream * me, const char * s)
2.1       frystyk   306: {
                    307:     return HTTPReceive_put_block(me, s, (int) strlen(s));
                    308: }
                    309: 
                    310: PRIVATE int HTTPReceive_put_character (HTStream * me, char c)
                    311: {
                    312:     return HTTPReceive_put_block(me, &c, 1);
                    313: }
                    314: 
                    315: PRIVATE int HTTPReceive_flush (HTStream * me)
                    316: {
                    317:     return (*me->target->isa->flush)(me->target);
                    318: }
                    319: 
                    320: PRIVATE int HTTPReceive_free (HTStream * me)
                    321: {
                    322:     int status = HT_OK;
                    323:     if (me->target) {
                    324:        if ((status = (*me->target->isa->_free)(me->target)) == HT_WOULD_BLOCK)
                    325:            return HT_WOULD_BLOCK;
                    326:     }
2.2       frystyk   327:     HTChunk_delete(me->buffer);
2.11      frystyk   328:     HT_FREE(me);
2.1       frystyk   329:     return status;
                    330: }
                    331: 
                    332: PRIVATE int HTTPReceive_abort (HTStream * me, HTList * e)
                    333: {
2.18      frystyk   334:     if (me->target) (*me->target->isa->abort)(me->target, e);
2.2       frystyk   335:     HTChunk_delete(me->buffer);
2.11      frystyk   336:     HT_FREE(me);
2.12      eric      337:     if (PROT_TRACE) HTTrace("HTTPReceive. ABORTING...\n");
2.1       frystyk   338:     return HT_ERROR;
                    339: }
                    340: 
                    341: /*     HTTPReceive Stream
                    342: **     -----------------
                    343: */
2.14      frystyk   344: PRIVATE const HTStreamClass HTTPReceiveClass =
2.1       frystyk   345: {              
                    346:     "HTTPReceive",
                    347:     HTTPReceive_flush,
                    348:     HTTPReceive_free,
                    349:     HTTPReceive_abort,
                    350:     HTTPReceive_put_character,
                    351:     HTTPReceive_put_string,
                    352:     HTTPReceive_put_block
                    353: };
                    354: 
                    355: PRIVATE HTStream * HTTPReceive_new (HTRequest * request, https_info * http)
                    356: {
2.11      frystyk   357:     HTStream * me;
                    358:     if ((me = (HTStream  *) HT_CALLOC(1, sizeof(HTStream))) == NULL)
                    359:         HT_OUTOFMEM("HTTPReceive_new");
2.1       frystyk   360:     me->isa = &HTTPReceiveClass;
                    361:     me->request = request;
2.9       frystyk   362:     me->http = http;
2.1       frystyk   363:     me->state = EOL_BEGIN;    
2.2       frystyk   364:     me->buffer = HTChunk_new(128);              /* Sufficiant for most URLs */
2.18      frystyk   365:     if (STREAM_TRACE) HTTrace("HTTP Request Stream %p created\n", me);
2.1       frystyk   366:     return me;
                    367: }
                    368: 
                    369: /* ------------------------------------------------------------------------- */
                    370: 
                    371: /*     HTServHTTP
                    372: **     ----------
                    373: **     Serv Document using HTTP.
                    374: **     returns HT_ERROR or HT_OK
                    375: */
2.23    ! frystyk   376: PRIVATE int ServEvent (SOCKET soc, void * pVoid, HTEventType type);
        !           377: 
        !           378: PUBLIC int HTServHTTP (SOCKET soc, HTRequest * request)
2.1       frystyk   379: {
2.18      frystyk   380:     HTNet * net = HTRequest_net(request);
2.1       frystyk   381:     https_info * http;                     /* Specific protocol information */
2.18      frystyk   382: 
2.1       frystyk   383:     /*
                    384:     ** Initiate a new https object and bind to request object
                    385:     ** This is actually state HTTPS_BEGIN, but it can't be in the state
                    386:     ** machine as we need the object first (chicken and egg problem).
                    387:     */
2.23    ! frystyk   388:     if (PROT_TRACE) HTTrace("Serv HTTP... on socket %d\n", soc);
        !           389:     if ((http = (https_info *) HT_CALLOC(1, sizeof(https_info))) == NULL)
        !           390:        HT_OUTOFMEM("HTServHTTP");
        !           391:     http->server = request;
        !           392:     http->state = HTTPS_BEGIN;
        !           393:     http->clients = HTList_new();
        !           394:     HTNet_setContext(net, http);
        !           395: 
        !           396:     /* 
        !           397:     ** Create the stream pipe FROM the channel to the server request.
        !           398:     */
        !           399:     net->readStream = HTTPReceive_new(request, http);
        !           400:     HTRequest_setOutputConnected(request, YES);
        !           401:     http->state = HTTPS_BEGIN;
        !           402: 
        !           403:     HTNet_setEventCallback(net, ServEvent);
        !           404:     HTNet_setEventParam(net, http);  /* callbacks get http* */
        !           405: 
        !           406:     return ServEvent(soc, http, HTEvent_BEGIN);                /* get it started - ops is ignored */
        !           407: }
        !           408: 
        !           409: PRIVATE int ServEvent (SOCKET soc, void * pVoid, HTEventType type)
        !           410: {
        !           411:     https_info * http = (https_info *)pVoid;
        !           412:     int status = HT_ERROR;
        !           413:     HTNet * net = http->net;
        !           414:     HTRequest * request = HTNet_request(net);
        !           415: 
        !           416:     if (!net || !request) {
        !           417:        if (PROT_TRACE) HTTrace("Serv HTTP... Invalid argument\n");
        !           418:        return HT_ERROR;
        !           419:     }
2.18      frystyk   420: 
2.23    ! frystyk   421:     if (type == HTEvent_CLOSE) {                             /* Interrupted */
2.6       frystyk   422:        ServerCleanup(request, net, HT_INTERRUPTED);
2.1       frystyk   423:        return HT_OK;
                    424:     } else
2.18      frystyk   425:        http = (https_info *) HTNet_context(net);       /* Get existing copy */
2.1       frystyk   426:  
                    427:     /* Now jump into the machine. We know the state from the previous run */
                    428:     while (1) {
                    429:        switch (http->state) {
2.18      frystyk   430:        case HTTPS_BEGIN:
                    431:        {
                    432:            /*
                    433:            ** Create the request to handle the request and inherit the old
                    434:            ** context
                    435:            */
                    436:            HTRequest * client = HTRequest_new();
                    437:            void * context = HTRequest_context(request);
                    438:            if (context) HTRequest_setContext(client, context);
2.19      frystyk   439:            HTRequest_setOutputConnected(client, NO);
                    440:            HTRequest_setGnHd(client, HTRequest_gnHd(request));
                    441:            HTRequest_setRsHd(client, HTRequest_rsHd(request));
                    442:            HTRequest_setEnHd(client, HTRequest_enHd(request));
2.18      frystyk   443:            HTList_addObject(http->clients, client);
                    444:            
                    445:            /*
                    446:            ** Create the HTTP output stream for generating the reply
                    447:            ** FROM the client request to the channel
                    448:            */
                    449:            {
                    450:                HTOutputStream * output = HTNet_getOutput(net, NULL, 0);
                    451:                HTStream * app = HTTPReply_new(client, http,(HTStream*)output);
                    452:                HTRequest_setOutputStream(client, app);
                    453:                HTRequest_setOutputFormat(client, WWW_SOURCE);
                    454:            }
                    455:            http->state = HTTPS_NEED_REQUEST;
                    456:        }
                    457:        break;
2.1       frystyk   458: 
2.18      frystyk   459:        case HTTPS_NEED_REQUEST:
2.23    ! frystyk   460:            if (type == HTEvent_READ || type == HTEvent_BEGIN) {
        !           461:                status = HTHost_read(net->host, net);
2.3       frystyk   462:                if (status == HT_WOULD_BLOCK)
                    463:                    return HT_OK;
2.18      frystyk   464:                else if (status == HT_CLOSED)
2.6       frystyk   465:                    http->state = HTTPS_OK;
2.18      frystyk   466:                else if (status==HT_LOADED || status==HT_PAUSE) {
                    467:                    http->state = HTTPS_LOAD_CLIENT;
                    468:                } else
2.3       frystyk   469:                    http->state = HTTPS_ERROR;
                    470:            } else
2.2       frystyk   471:                http->state = HTTPS_ERROR;
2.1       frystyk   472:            break;
                    473: 
2.18      frystyk   474:        case HTTPS_LOAD_CLIENT:
                    475:        {
                    476:            HTRequest * client = HTList_removeFirstObject(http->clients);
                    477:            HTLoad(client, NO);
                    478:            http->state = HTTPS_BEGIN;
                    479:            break;
                    480:        }
                    481: 
                    482:        case HTTPS_OK:
2.8       frystyk   483:            ServerCleanup(request, net, HT_IGNORE);
2.18      frystyk   484:            return HT_OK;
2.6       frystyk   485: 
2.18      frystyk   486:        case HTTPS_ERROR:
2.6       frystyk   487:            ServerCleanup(request, net, HT_ERROR);
2.1       frystyk   488:            return HT_OK;
                    489:        }
                    490:     }
2.3       frystyk   491: }
2.6       frystyk   492: 

Webmaster