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