Annotation of libwww/Library/src/HTTPServ.c, revision 2.15
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.
6: **
7: ** This module implments the HTTP protocol as a state machine
8: **
9: ** History:
10: ** Dec 95 HFN Written with Christmas in my eyes
11: **
12: */
13:
14: /* Library include files */
2.14 frystyk 15: #include "sysdep.h"
2.1 frystyk 16: #include "HTUtils.h"
17: #include "HTString.h"
18: #include "HTParse.h"
19: #include "HTWWWStr.h"
20: #include "HTTCP.h"
21: #include "HTSocket.h"
22: #include "HTAlert.h"
23: #include "HTError.h"
24: #include "HTAccess.h"
2.2 frystyk 25: #include "HTWriter.h"
2.1 frystyk 26: #include "HTChunk.h"
27: #include "HTReqMan.h"
2.9 frystyk 28: #include "HTConLen.h"
2.1 frystyk 29: #include "HTNetMan.h"
2.9 frystyk 30: #include "HTMIMERq.h"
2.1 frystyk 31: #include "HTTPUtil.h"
2.2 frystyk 32: #include "HTTPRes.h"
2.1 frystyk 33: #include "HTTPServ.h" /* Implements */
34:
35: /* Macros and other defines */
36: #define PUTC(c) (*me->target->isa->put_character)(me->target, c)
37: #define PUTS(s) (*me->target->isa->put_string)(me->target, s)
38: #define PUTBLOCK(b, l) (*me->target->isa->put_block)(me->target, b, l)
39: #define FREE_TARGET (*me->target->isa->_free)(me->target)
40: #define ABORT_TARGET (*me->target->isa->abort)(me->target, e)
41:
42: /* Final states have negative value */
43: typedef enum _HTTPState {
2.6 frystyk 44: HTTPS_ERROR = -2,
45: HTTPS_OK = -1,
2.1 frystyk 46: HTTPS_BEGIN = 0,
2.3 frystyk 47: HTTPS_NEED_REQUEST
2.1 frystyk 48: } HTTPState;
49:
50: /* This is the context object for the this module */
51: typedef struct _https_info {
52: HTTPState state; /* Current State of the connection */
2.9 frystyk 53: char * version; /* Version for the reply */
2.10 frystyk 54: HTRequest * client; /* This is out client request */
2.1 frystyk 55: } https_info;
56:
57: /* The HTTP Receive Stream */
58: struct _HTStream {
2.14 frystyk 59: const HTStreamClass * isa;
2.1 frystyk 60: HTStream * target;
61: HTRequest * request;
2.9 frystyk 62: https_info * http;
63: HTRequest * client;
2.15 ! frystyk 64: HTEOLState state;
2.1 frystyk 65: HTChunk * buffer;
66: BOOL transparent;
67: };
68:
69: /* ------------------------------------------------------------------------- */
2.8 frystyk 70:
71: /* ServerCleanup
72: ** -------------
73: ** This function cleans up after the request
74: ** Returns YES on OK, else NO
75: */
76: PRIVATE int ServerCleanup (HTRequest * req, HTNet * net, int status)
77: {
78: https_info * http = (https_info *) net->context;
79:
80: /* Free stream with data TO network */
81: if (req->input_stream) {
82: if (status == HT_INTERRUPTED)
83: (*req->input_stream->isa->abort)(req->input_stream, NULL);
84: else
85: (*req->input_stream->isa->_free)(req->input_stream);
86: req->input_stream = NULL;
87: }
88:
89: /* Remove the net object and our own context structure for http */
90: HTNet_delete(net, req->internal ? HT_IGNORE : status);
2.11 frystyk 91: HT_FREE(http->version);
92: HT_FREE(http);
2.8 frystyk 93: return YES;
94: }
95:
96: /* ------------------------------------------------------------------------- */
2.6 frystyk 97: /* REPLY STREAM */
98: /* ------------------------------------------------------------------------- */
2.1 frystyk 99:
2.6 frystyk 100: /*
101: ** This is our handle to the server reply stream when data is coming
2.9 frystyk 102: ** back from our "client" request. It is responsible for setting up the
103: ** remaining streams in order to produce a complete HTTP output.
104: ** If we have a HTTP 1.x response then forward untouched.
105: **
106: ** BUG: We should look at the version string before generating response!
2.6 frystyk 107: */
2.9 frystyk 108: PRIVATE int MakeReplyPipe (HTStream *me, HTRequest *server, HTRequest *client)
109: {
110: char * response_line = NULL;
111: me->transparent = YES;
112:
113: /* Check if we can forward the response untouched */
114: if (client->net) {
115: HTdns * cdns = client->net->dns;
116: char * s_class = HTDNS_serverClass(cdns);
117: int version = HTDNS_serverVersion(cdns);
118: /* We are not using the version info for the moment */
119: if (s_class && !strcasecomp(s_class, "http")) {
2.12 eric 120: if (STREAM_TRACE) HTTrace("HTTP Reply.. Direct output\n");
2.9 frystyk 121: return HT_OK;
122: }
123: }
124:
125: /* Set up a small buffer for the response headers */
126: me->target = HTBuffer_new(me->target, server, 256);
127:
128: /* Generate the Response line */
129: {
130: HTAlertCallback *cbf = HTAlert_find(HT_A_MESSAGE);
131: if (cbf) {
132: HTAlertPar * reply = HTAlert_newReply();
133: if ((*cbf)(client, HT_A_MESSAGE, HT_MSG_NULL, NULL,
134: client->error_stack, reply))
135: response_line = HTAlert_replyMessage(reply);
136: HTAlert_deleteReply(reply);
137: }
138:
139: /* Output the response */
140: if (response_line) {
141: PUTS(response_line);
2.11 frystyk 142: HT_FREE(response_line);
2.9 frystyk 143: } else {
2.13 frystyk 144: PUTS("HTTP/1.0 500 Internal");
2.9 frystyk 145: PUTC(CR);
146: PUTC(LF);
147: }
148: }
149:
150: /*
151: ** We now have to create the rest of the response stream. We see whether
152: ** there is a data object or not by looking at the Content Type of the
153: ** client anchor.
154: */
155: me->target = (HTAnchor_format(client->anchor) == WWW_UNKNOWN) ?
156: HTTPResponse_new(server, me->target, YES) :
157: HTMIMERequest_new(server, HTTPResponse_new(server,me->target,NO), YES);
158:
159: /* Here we should put out any BODY for the error message */
160:
161: return (*me->target->isa->flush)(me->target);
162: }
2.6 frystyk 163:
2.14 frystyk 164: PRIVATE int HTTPReply_put_block (HTStream * me, const char * b, int l)
2.1 frystyk 165: {
2.9 frystyk 166: if (me->transparent)
167: return b ? PUTBLOCK(b, l) : HT_OK;
168: else {
169: MakeReplyPipe(me, me->request, me->client);
170: return b ? PUTBLOCK(b, l) : HT_OK;
171: }
2.6 frystyk 172: }
173:
2.14 frystyk 174: PRIVATE int HTTPReply_put_string (HTStream * me, const char * s)
2.6 frystyk 175: {
2.9 frystyk 176: return HTTPReply_put_block(me, s, strlen(s));
2.6 frystyk 177: }
178:
179: PRIVATE int HTTPReply_put_character (HTStream * me, char c)
180: {
2.9 frystyk 181: return HTTPReply_put_block(me, &c, 1);
2.6 frystyk 182: }
183:
184: PRIVATE int HTTPReply_flush (HTStream * me)
185: {
2.9 frystyk 186: int status = HTTPReply_put_block(me, NULL, 0);
187: return status==HT_OK ? (*me->target->isa->flush)(me->target) : status;
2.6 frystyk 188: }
2.1 frystyk 189:
2.6 frystyk 190: PRIVATE int HTTPReply_free (HTStream * me)
191: {
2.9 frystyk 192: int status = HTTPReply_flush(me);
2.12 eric 193: if (STREAM_TRACE) HTTrace("HTTPReply... Freeing server stream\n");
2.9 frystyk 194: if (status != HT_WOULD_BLOCK) {
195: HTNet * snet = me->request->net;
196: if ((status = FREE_TARGET) == HT_WOULD_BLOCK) return HT_WOULD_BLOCK;
197: #if 0
198: /* We can't do this until we get a better event loop */
2.15 ! frystyk 199: if (HTNet_persistent(snet)) {
2.9 frystyk 200: if (STREAM_TRACE)
2.12 eric 201: HTTrace("HTTPReply... Persistent conenction\n");
2.9 frystyk 202: HTEvent_Register(snet->sockfd, me->request, (SockOps) FD_READ,
203: snet->cbf, snet->priority);
204: HTRequest_clear(me->request);
205: } else {
206: ServerCleanup(me->request, snet, HT_IGNORE);
2.8 frystyk 207: HTRequest_delete(me->request);
2.9 frystyk 208: HTRequest_removeDest(me->client);
209: }
210: #else
211: ServerCleanup(me->request, snet, HT_IGNORE);
212: HTRequest_delete(me->request);
213: #endif
2.1 frystyk 214: }
2.11 frystyk 215: HT_FREE(me);
2.6 frystyk 216: return HT_OK;
217: }
218:
219: PRIVATE int HTTPReply_abort (HTStream * me, HTList * e)
220: {
2.9 frystyk 221: HTNet * snet = me->request->net;
222: if (!me->transparent) {
223: HTRequest_addError(me->client, ERR_FATAL, NO, HTERR_INTERNAL,
224: NULL, 0, "HTTPReply_abort");
225: MakeReplyPipe(me, me->request, me->client);
226: }
2.12 eric 227: if (STREAM_TRACE) HTTrace("HTTPReply... ABORTING\n");
2.6 frystyk 228: if (me->target) ABORT_TARGET;
2.9 frystyk 229: #if 0
230: /* We can't do this until we get a better event loop */
2.15 ! frystyk 231: if (HTNet_persistent(snet)) {
2.9 frystyk 232: if (STREAM_TRACE)
2.12 eric 233: HTTrace("HTTPReply... Persistent conenction\n");
2.9 frystyk 234: HTEvent_Register(snet->sockfd, me->request, (SockOps) FD_READ,
235: snet->cbf, snet->priority);
236: HTRequest_clear(me->request);
237: } else {
238: ServerCleanup(me->request, snet, HT_IGNORE);
239: HTRequest_delete(me->request);
240: HTRequest_removeDest(me->client);
241: }
242: #else
243: ServerCleanup(me->request, snet, HT_IGNORE);
244: HTRequest_delete(me->request);
245: #endif
2.11 frystyk 246: HT_FREE(me);
2.6 frystyk 247: return HT_ERROR;
248: }
249:
250: /* HTTPReply Stream
251: ** -----------------
252: */
2.14 frystyk 253: PRIVATE const HTStreamClass HTTPReplyClass =
2.6 frystyk 254: {
255: "HTTPReply",
256: HTTPReply_flush,
257: HTTPReply_free,
258: HTTPReply_abort,
259: HTTPReply_put_character,
260: HTTPReply_put_string,
261: HTTPReply_put_block
262: };
2.1 frystyk 263:
2.9 frystyk 264: PRIVATE HTStream * HTTPReply_new (HTRequest * request, HTRequest * client,
265: HTStream * target)
2.6 frystyk 266: {
2.11 frystyk 267: HTStream * me;
268: if ((me = (HTStream *) HT_CALLOC(1, sizeof(HTStream))) == NULL)
269: HT_OUTOFMEM("HTTPReply_new");
2.6 frystyk 270: me->isa = &HTTPReplyClass;
271: me->target = target;
272: me->request = request;
2.9 frystyk 273: me->client = client;
2.6 frystyk 274: return me;
2.1 frystyk 275: }
276:
2.6 frystyk 277: /* ------------------------------------------------------------------------- */
278: /* RECEIVE STREAM */
279: /* ------------------------------------------------------------------------- */
280:
2.1 frystyk 281: /*
282: ** Scan the request line for METHOD, URI and VERSION
283: ** Returns: HT_OK if 1.x request and OK
284: ** HT_LOADED if 0.9 request and OK
285: ** HT_ERROR if invalid request line
286: */
287: PRIVATE int ParseRequest (HTStream * me)
288: {
2.3 frystyk 289: HTRequest * request = me->request;
2.2 frystyk 290: char * line = HTChunk_data(me->buffer);
2.6 frystyk 291: char * method_str = HTNextField(&line);
292: char * request_uri = HTNextField(&line);
293: char * version_str = HTNextField(&line);
294:
295: /* Check if method is allowed */
296: if (!method_str || (request->method=HTMethod_enum(method_str))==METHOD_INVALID) {
297: HTRequest_addError(request, ERR_FATAL, NO, HTERR_NOT_ALLOWED,
298: NULL, 0, "ParseRequest");
299: return HT_ERROR;
300: }
2.2 frystyk 301:
2.6 frystyk 302: /* Find an anchor for the request URI */
303: if (request_uri) {
304: char * uri = HTParse(request_uri, "file:", PARSE_ALL);
305: request->anchor = (HTParentAnchor *) HTAnchor_findAddress(uri);
2.11 frystyk 306: HT_FREE(uri);
2.1 frystyk 307: } else {
2.6 frystyk 308: HTRequest_addError(request, ERR_FATAL, NO, HTERR_BAD_REQUEST,
2.1 frystyk 309: NULL, 0, "ParseRequest");
310: return HT_ERROR;
311: }
312:
2.6 frystyk 313: /* Get ready to get the rest of the request */
314: if (version_str) {
2.8 frystyk 315: me->target = HTStreamStack(WWW_MIME_HEAD, request->debug_format,
316: request->debug_stream, request, NO);
2.9 frystyk 317: StrAllocCopy(me->http->version, version_str);
2.1 frystyk 318: return HT_OK;
2.2 frystyk 319: } else {
2.12 eric 320: if (PROT_TRACE) HTTrace("Request Line is formatted as 0.9\n");
2.3 frystyk 321: return HT_LOADED;
2.1 frystyk 322: }
323: }
324:
325: /*
326: ** Searches for HTTP Request Line before going into transparent mode
327: */
2.14 frystyk 328: PRIVATE int HTTPReceive_put_block (HTStream * me, const char * b, int l)
2.1 frystyk 329: {
2.6 frystyk 330: if (!me->transparent) {
2.14 frystyk 331: const char *p=b;
2.6 frystyk 332: while (l>0 && *p!=CR && *p!=LF) l--, p++;
333: HTChunk_putb(me->buffer, b, p-b);
334: if (*p==CR || *p==LF) {
335: int status = ParseRequest(me);
336: HTChunk_clear(me->buffer);
337: if (status != HT_OK) return status;
338: me->transparent = YES;
339: b=p;
340: }
341: }
342: if (l > 0) {
343: int status = PUTBLOCK(b, l);
344: if (status == HT_LOADED) me->transparent = NO;
345: return status;
2.1 frystyk 346: }
347: return HT_OK;
348: }
349:
2.14 frystyk 350: PRIVATE int HTTPReceive_put_string (HTStream * me, const char * s)
2.1 frystyk 351: {
352: return HTTPReceive_put_block(me, s, (int) strlen(s));
353: }
354:
355: PRIVATE int HTTPReceive_put_character (HTStream * me, char c)
356: {
357: return HTTPReceive_put_block(me, &c, 1);
358: }
359:
360: PRIVATE int HTTPReceive_flush (HTStream * me)
361: {
362: return (*me->target->isa->flush)(me->target);
363: }
364:
365: PRIVATE int HTTPReceive_free (HTStream * me)
366: {
367: int status = HT_OK;
368: if (me->target) {
369: if ((status = (*me->target->isa->_free)(me->target)) == HT_WOULD_BLOCK)
370: return HT_WOULD_BLOCK;
371: }
2.2 frystyk 372: HTChunk_delete(me->buffer);
2.11 frystyk 373: HT_FREE(me);
2.1 frystyk 374: return status;
375: }
376:
377: PRIVATE int HTTPReceive_abort (HTStream * me, HTList * e)
378: {
379: if (me->target) ABORT_TARGET;
2.2 frystyk 380: HTChunk_delete(me->buffer);
2.11 frystyk 381: HT_FREE(me);
2.12 eric 382: if (PROT_TRACE) HTTrace("HTTPReceive. ABORTING...\n");
2.1 frystyk 383: return HT_ERROR;
384: }
385:
386: /* HTTPReceive Stream
387: ** -----------------
388: */
2.14 frystyk 389: PRIVATE const HTStreamClass HTTPReceiveClass =
2.1 frystyk 390: {
391: "HTTPReceive",
392: HTTPReceive_flush,
393: HTTPReceive_free,
394: HTTPReceive_abort,
395: HTTPReceive_put_character,
396: HTTPReceive_put_string,
397: HTTPReceive_put_block
398: };
399:
400: PRIVATE HTStream * HTTPReceive_new (HTRequest * request, https_info * http)
401: {
2.11 frystyk 402: HTStream * me;
403: if ((me = (HTStream *) HT_CALLOC(1, sizeof(HTStream))) == NULL)
404: HT_OUTOFMEM("HTTPReceive_new");
2.1 frystyk 405: me->isa = &HTTPReceiveClass;
406: me->request = request;
2.9 frystyk 407: me->http = http;
2.1 frystyk 408: me->state = EOL_BEGIN;
2.2 frystyk 409: me->buffer = HTChunk_new(128); /* Sufficiant for most URLs */
2.1 frystyk 410: return me;
411: }
412:
413: /* ------------------------------------------------------------------------- */
414:
415: /* HTServHTTP
416: ** ----------
417: ** Serv Document using HTTP.
418: ** returns HT_ERROR or HT_OK
419: */
420: PUBLIC int HTServHTTP (SOCKET soc, HTRequest * request, SockOps ops)
421: {
422: int status = HT_ERROR;
2.6 frystyk 423: HTNet * net = request->net; /* Server information */
2.1 frystyk 424: https_info * http; /* Specific protocol information */
425:
426: /*
427: ** Initiate a new https object and bind to request object
428: ** This is actually state HTTPS_BEGIN, but it can't be in the state
429: ** machine as we need the object first (chicken and egg problem).
430: */
431: if (ops == FD_NONE) {
432: if (PROT_TRACE)
2.12 eric 433: HTTrace("HTTP Serve.. request %p on socket %d\n",
2.1 frystyk 434: request, soc);
2.11 frystyk 435: if ((http = (https_info *) HT_CALLOC(1, sizeof(https_info))) == NULL)
436: HT_OUTOFMEM("HTServHTTP");
2.1 frystyk 437: http->state = HTTPS_BEGIN;
438: net->context = http;
439: } else if (ops == FD_CLOSE) { /* Interrupted */
2.6 frystyk 440: ServerCleanup(request, net, HT_INTERRUPTED);
2.1 frystyk 441: return HT_OK;
442: } else
443: http = (https_info *) net->context; /* Get existing copy */
444:
445: /* Now jump into the machine. We know the state from the previous run */
446: while (1) {
447: switch (http->state) {
448: case HTTPS_BEGIN:
449: status = HTDoAccept(net);
450: if (status == HT_OK) {
2.6 frystyk 451:
452: /* Setup Request parser stream */
453: net->target = HTTPReceive_new(request, http);
454:
455: http->state = HTTPS_NEED_REQUEST;
2.1 frystyk 456: } else {
2.6 frystyk 457: ServerCleanup(request, net, HT_ERROR);
2.1 frystyk 458: return HT_ERROR;
459: }
460: break;
461:
462: case HTTPS_NEED_REQUEST:
2.3 frystyk 463: if (ops == FD_READ || ops == FD_NONE) {
2.15 ! frystyk 464: status = HTChannel_readSocket(request, net);
2.3 frystyk 465: if (status == HT_WOULD_BLOCK)
466: return HT_OK;
2.8 frystyk 467: else if (status == HT_PAUSE) {
2.10 frystyk 468: http->client = HTRequest_dup(request);
2.9 frystyk 469:
470: /* Set the right client headers */
2.10 frystyk 471: HTRequest_setGnHd(http->client, DEFAULT_GENERAL_HEADERS);
2.9 frystyk 472:
2.8 frystyk 473: /*
474: ** If we have a data object in the request then link the
475: ** two request objects together
476: */
477: if (HTMethod_hasEntity(request->method))
2.10 frystyk 478: HTRequest_addDestination(request, http->client);
2.9 frystyk 479:
480: /*
481: ** Set up our reply stream. This is responsible for
482: ** generating a HTTP reply
483: */
2.10 frystyk 484: http->client->output_stream = request->output_stream =
485: HTTPReply_new(request, http->client,
2.9 frystyk 486: HTWriter_new(request->net,YES));
487:
488: /* Start the load of the "client" request */
2.10 frystyk 489: return HTLoad(http->client, NO) == YES ? HT_OK : HT_ERROR;
2.6 frystyk 490: } else if (status == HT_CLOSED)
491: http->state = HTTPS_OK;
492: else
2.3 frystyk 493: http->state = HTTPS_ERROR;
2.6 frystyk 494: } else if (ops == FD_WRITE) {
2.10 frystyk 495: #if 0
2.7 frystyk 496: if (HTRequest_mainDestination(request)) {
2.3 frystyk 497: HTNet * dest = request->mainDestination->net;
498: HTEvent_Register(dest->sockfd, dest->request,
499: (SockOps) FD_READ,
500: dest->cbf, dest->priority);
501: }
2.10 frystyk 502: #else
503: if (http->client && http->client->net) {
504: HTNet * dnet = http->client->net;
505: HTEvent_Register(dnet->sockfd, http->client,
506: (SockOps) FD_READ, dnet->cbf, dnet->priority);
507: }
508: #endif
2.1 frystyk 509: return HT_OK;
2.3 frystyk 510: } else
2.2 frystyk 511: http->state = HTTPS_ERROR;
2.1 frystyk 512: break;
513:
2.6 frystyk 514: case HTTPS_OK:
2.8 frystyk 515: ServerCleanup(request, net, HT_IGNORE);
2.6 frystyk 516: break;
517:
2.1 frystyk 518: case HTTPS_ERROR:
2.8 frystyk 519: if (HTRequest_isPostWeb(request)) HTRequest_killPostWeb(request);
2.6 frystyk 520: ServerCleanup(request, net, HT_ERROR);
2.1 frystyk 521: return HT_OK;
522: break;
523: }
524: }
2.3 frystyk 525: }
2.6 frystyk 526:
Webmaster