OpenCores
URL https://opencores.org/ocsvn/openrisc_2011-10-31/openrisc_2011-10-31/trunk

Subversion Repositories openrisc_2011-10-31

[/] [openrisc/] [trunk/] [rtos/] [rtems/] [c/] [src/] [libnetworking/] [rtems_webserver/] [webs.c] - Blame information for rev 493

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 30 unneback
/*
2
 * webs.c -- GoAhead Embedded HTTP webs server
3
 *
4
 * Copyright (c) Go Ahead Software Inc., 1995-1999. All Rights Reserved.
5
 *
6
 * See the file "license.txt" for usage and redistribution license requirements
7
 */
8
 
9
/******************************** Description *********************************/
10
 
11
/*
12
 *      This module implements an embedded HTTP/1.1 webs server. It supports
13
 *      loadable URL handlers that define the nature of URL processing performed.
14
 */
15
 
16
/********************************* Includes ***********************************/
17
 
18
#include        "wsIntrn.h"
19
 
20
/******************************** Global Data *********************************/
21
 
22
websStatsType    websStats;                             /* Web access stats */
23
webs_t                  *webs;                                  /* Open connection list head */
24
sym_fd_t                 websMime;                              /* Set of mime types */
25
int                              websMax;                               /* List size */
26
int                              websPort;                              /* Listen port for server */
27
char_t                   websHost[64];                  /* Host name for the server */
28
char_t                   websIpaddr[64];                /* IP address for the server */
29
char_t                  *websHostUrl = NULL;    /* URL to access server */
30
 
31
/*********************************** Locals ***********************************/
32
/*
33
 *      Standard HTTP error codes
34
 */
35
 
36
websErrorType websErrors[] = {
37
        { 200, T("Data follows") },
38
        { 204, T("No Content") },
39
        { 301, T("Redirect") },
40
        { 302, T("Redirect") },
41
        { 304, T("User local copy") },
42
        { 400, T("Page not found") },
43
        { 401, T("Password Required") },
44
        { 404, T("Site or Page Not Found") },
45
        { 405, T("Access Denied") },
46
        { 500, T("Web Error") },
47
        { 503, T("Site Temporarily Unavailable. Try again") },
48
        { 0, NULL }
49
};
50
 
51
#if WEBS_LOG_SUPPORT
52
static char_t   websLogname[64] = T("log.txt"); /* Log filename */
53
static int              websLogFd;                                              /* Log file handle */
54
#endif
55
 
56
static int              websListenSock;                                 /* Listen socket */
57
 
58
/**************************** Forward Declarations ****************************/
59
 
60
static int               websAccept(int sid, char *ipaddr, int port);
61
static int               websAlloc(int sid);
62
static char_t   *websErrorMsg(int code);
63
static void      websFree(webs_t wp);
64
static void              websFreeVar(sym_t* sp);
65
static int               websGetInput(webs_t wp, char_t **ptext, int *nbytes);
66
static int               websParseFirst(webs_t wp, char_t *text);
67
static void      websParseRequest(webs_t wp);
68
static void      websReadEvent(webs_t wp);
69
static void              websSocketEvent(int sid, int mask, int data);
70
static void      websTimeout(long wp);
71
static void      websTimeoutCancel(webs_t wp);
72
static void              websMarkTime(webs_t wp);
73
static int               websGetTimeSinceMark(webs_t wp);
74
 
75
#if WEBS_LOG_SUPPORT
76
static void      websLog(webs_t wp, int code);
77
#endif
78
#if WEBS_IF_MODIFIED_SUPPORT
79
static time_t dateParse(time_t tip, char_t *cmd);
80
#endif
81
 
82
/*********************************** Code *************************************/
83
/*
84
 *      Open the GoAhead WebServer
85
 */
86
 
87
int websOpenServer(int port, int retries)
88
{
89
        websMimeType    *mt;
90
 
91
        a_assert(port > 0);
92
        a_assert(retries >= 0);
93
 
94
#if WEBS_PAGE_ROM
95
        websRomOpen();
96
#endif
97
 
98
/*
99
 *      Create a mime type lookup table for quickly determining the content type
100
 */
101
        websMime = symOpen(256);
102
        a_assert(websMime >= 0);
103
        for (mt = websMimeList; mt->type; mt++) {
104
                symEnter(websMime, mt->ext, valueString(mt->type, 0), 0);
105
        }
106
 
107
/*
108
 *      Open the URL handler module. The caller should create the required
109
 *      URL handlers after calling this function.
110
 */
111
        if (websUrlHandlerOpen() < 0) {
112
                return -1;
113
        }
114
 
115
#if WEBS_LOG_SUPPORT
116
/*
117
 *      Optional request log support
118
 */
119
        websLogFd = gopen(websLogname, O_CREAT | O_TRUNC | O_APPEND | O_WRONLY,
120
                0666);
121
        a_assert(websLogFd >= 0);
122
#endif
123
 
124
        return websOpenListen(port, retries);
125
}
126
 
127
/******************************************************************************/
128
/*
129
 *      Close the GoAhead WebServer
130
 */
131
 
132
void websCloseServer()
133
{
134
        webs_t  wp;
135
        int             wid;
136
 
137
/*
138
 *      Close the listen handle first then all open connections.
139
 */
140
        websCloseListen();
141
 
142
/*
143
 *      Close each open browser connection and free all resources
144
 */
145
        for (wid = websMax; webs && wid >= 0; wid--) {
146
                if ((wp = webs[wid]) == NULL) {
147
                        continue;
148
                }
149
                socketCloseConnection(wp->sid);
150
                websFree(wp);
151
        }
152
 
153
#if WEBS_LOG_SUPPORT
154
        if (websLogFd >= 0) {
155
                close(websLogFd);
156
                websLogFd = -1;
157
        }
158
#endif
159
 
160
#if WEBS_PAGE_ROM
161
        websRomClose();
162
#endif
163
        symClose(websMime, NULL);
164
        websFormClose();
165
        websUrlHandlerClose();
166
}
167
 
168
/******************************************************************************/
169
/*
170
 *      Open the GoAhead WebServer listen port
171
 */
172
 
173
int websOpenListen(int port, int retries)
174
{
175
        int             i, orig;
176
 
177
        a_assert(port > 0);
178
        a_assert(retries >= 0);
179
 
180
        orig = port;
181
/*
182
 *      Open the webs webs listen port. If we fail, try the next port.
183
 */
184
        for (i = 0; i <= retries; i++) {
185
                websListenSock = socketOpenConnection(NULL, port, websAccept, 0);
186
                if (websListenSock >= 0) {
187
                        break;
188
                }
189
                port++;
190
        }
191
        if (i > retries) {
192
                error(E_L, E_USER, T("Couldn't open a socket on ports %d - %d"),
193
                        orig, port - 1);
194
                return -1;
195
        }
196
        goahead_trace(0, T("webs: Listening for HTTP requests on port %d\n"), port);
197
 
198
/*
199
 *      Determine the full URL address to access the home page for this web server
200
 */
201
        websPort = port;
202
        bfreeSafe(B_L, websHostUrl);
203
        websHostUrl = NULL;
204
        if (port == 80) {
205
                websHostUrl = bstrdup(B_L, websHost);
206
        } else {
207
                gsnprintf(&websHostUrl, WEBS_MAX_URL + 80, T("%s:%d"), websHost, port);
208
        }
209
        return port;
210
}
211
 
212
/******************************************************************************/
213
/*
214
 *      Close webs listen port
215
 */
216
 
217
void websCloseListen()
218
{
219
        if (websListenSock >= 0) {
220
                socketCloseConnection(websListenSock);
221
                websListenSock = -1;
222
        }
223
        bfreeSafe(B_L, websHostUrl);
224
        websHostUrl = NULL;
225
}
226
 
227
/******************************************************************************/
228
/*
229
 *      Accept a connection
230
 */
231
 
232
static int websAccept(int sid, char *ipaddr, int port)
233
{
234
        webs_t  wp;
235
        int             wid;
236
 
237
        a_assert(ipaddr && *ipaddr);
238
        a_assert(sid >= 0);
239
        a_assert(port >= 0);
240
 
241
/*
242
 *      Allocate a new handle for this accepted connection. This will allocate
243
 *      a webs_t structure in the webs[] list
244
 */
245
        if ((wid = websAlloc(sid)) < 0) {
246
                return -1;
247
        }
248
        wp = webs[wid];
249
        a_assert(wp);
250
 
251
        ascToUni(wp->ipaddr, ipaddr, sizeof(wp->ipaddr));
252
 
253
/*
254
 *      Check if this is a request from a browser on this system. This is useful
255
 *      to know for permitting administrative operations only for local access
256
 */
257
        if (gstrcmp(wp->ipaddr, T("127.0.0.1")) == 0 ||
258
                        gstrcmp(wp->ipaddr, websIpaddr) == 0 ||
259
                        gstrcmp(wp->ipaddr, websHost) == 0) {
260
                wp->flags |= WEBS_LOCAL_REQUEST;
261
        }
262
 
263
/*
264
 *      Arrange for websSocketEvent to be called when read data is available
265
 */
266
        socketCreateHandler(sid, SOCKET_READABLE , websSocketEvent, (int) wp);
267
 
268
/*
269
 *      Arrange for a timeout to kill hung requests
270
 */
271
        wp->timeout = emfCreateTimer(WEBS_TIMEOUT, websTimeout, (long) wp);
272
        goahead_trace(5, T("webs: accept request\n"));
273
        return 0;
274
}
275
 
276
/******************************************************************************/
277
/*
278
 *      The webs socket handler.  Called in response to I/O. We just pass control
279
 *      to the relevant read or write handler. A pointer to the webs structure
280
 *      is passed as an (int) in iwp.
281
 */
282
 
283
static void websSocketEvent(int sid, int mask, int iwp)
284
{
285
        webs_t  wp;
286
 
287
        wp = (webs_t) iwp;
288
        a_assert(wp);
289
 
290
        if (! websValid(wp)) {
291
                return;
292
        }
293
 
294
        if (mask & SOCKET_READABLE) {
295
                websReadEvent(wp);
296
        }
297
        if (mask & SOCKET_WRITABLE) {
298
                if (wp->writeSocket) {
299
                        (*wp->writeSocket)(wp);
300
                }
301
        }
302
}
303
 
304
/******************************************************************************/
305
/*
306
 *      The webs read handler. This is the primary read event loop. It uses a
307
 *      state machine to track progress while parsing the HTTP request.
308
 *      Note: we never block as the socket is always in non-blocking mode.
309
 */
310
 
311
static void websReadEvent(webs_t wp)
312
{
313
        char_t  *text;
314
        int             rc, nbytes, len, done;
315
 
316
        a_assert(wp);
317
        a_assert(websValid(wp));
318
 
319
        websMarkTime(wp);
320
 
321
/*
322
 *      Read as many lines as possible. socketGets is called to read the header
323
 *      and socketRead is called to read posted data.
324
 */
325
        text = NULL;
326
        for (done = 0; !done; ) {
327
                if (text) {
328
                        bfree(B_L, text);
329
                        text = NULL;
330
                }
331
 
332
/*
333
 *              Get more input into "text". Returns 0, if more data is needed
334
 *              to continue, -1 if finished with the request, or 1 if all
335
 *              required data is available for current state.
336
 */
337
                while ((rc = websGetInput(wp, &text, &nbytes)) == 0) {
338
                        ;
339
                }
340
 
341
/*
342
 *              websGetInput returns -1 if it finishes with the request
343
 */
344
                if (rc < 0) {
345
                        break;
346
                }
347
 
348
/*
349
 *              This is the state machine for the web server.
350
 */
351
                switch(wp->state) {
352
                case WEBS_BEGIN:
353
/*
354
 *                      Parse the first line of the Http header
355
 */
356
                        if (websParseFirst(wp, text) < 0) {
357
                                done++;
358
                                break;
359
                        }
360
                        wp->state = WEBS_HEADER;
361
                        break;
362
 
363
                case WEBS_HEADER:
364
/*
365
 *                      Store more of the HTTP header. As we are doing line reads, we
366
 *                      need to separate the lines with '\n'
367
 */
368
                        if (ringqLen(&wp->header) > 0) {
369
                                ringqPutstr(&wp->header, T("\n"));
370
                        }
371
                        ringqPutstr(&wp->header, text);
372
                        break;
373
 
374
                case WEBS_POST_CLEN:
375
/*
376
 *                      POST request with content specified by a content length
377
 */
378
                        if (wp->query) {
379
                                if (wp->query[0] && !(wp->flags & WEBS_POST_DATA)) {
380
/*
381
 *                                      Special case where the POST request also had query data
382
 *                                      specified in the URL, ie. url?query_data. In this case
383
 *                                      the URL query data is separated by a '&' from the posted
384
 *                                      query data.
385
 */
386
                                        len = gstrlen(wp->query);
387
                                        wp->query = brealloc(B_L, wp->query, (len + gstrlen(text) +
388
                                                2) * sizeof(char_t));
389
                                        wp->query[len++] = '&';
390
                                        gstrcpy(&wp->query[len], text);
391
 
392
                                } else {
393
/*
394
 *                                      The existing query data came from the POST request so just
395
 *                                      append it.
396
 */
397
                                        len = gstrlen(wp->query);
398
                                        wp->query = brealloc(B_L, wp->query, (len +     gstrlen(text) +
399
                                                1) * sizeof(char_t));
400
                                        if (wp->query) {
401
                                                gstrcpy(&wp->query[len], text);
402
                                        }
403
                                }
404
 
405
                        } else {
406
                                wp->query = bstrdup(B_L, text);
407
                        }
408
/*
409
 *                      Calculate how much more post data is to be read.
410
 */
411
                        wp->flags |= WEBS_POST_DATA;
412
                        wp->clen -= nbytes;
413
                        if (wp->clen > 0) {
414
                                if (nbytes > 0) {
415
                                        done++;
416
                                        break;
417
                                }
418
                                done++;
419
                                break;
420
                        }
421
/*
422
 *                      No more data so process the request
423
 */
424
                        websUrlHandlerRequest(wp);
425
                        done++;
426
                        break;
427
 
428
                case WEBS_POST:
429
/*
430
 *                      POST without content-length specification
431
 */
432
                        if (wp->query && *wp->query && !(wp->flags & WEBS_POST_DATA)) {
433
                                len = gstrlen(wp->query);
434
                                wp->query = brealloc(B_L, wp->query, (len + gstrlen(text) +
435
                                        2) * sizeof(char_t));
436
                                if (wp->query) {
437
                                        wp->query[len++] = '&';
438
                                        gstrcpy(&wp->query[len], text);
439
                                }
440
 
441
                        } else {
442
                                wp->query = bstrdup(B_L, text);
443
                        }
444
                        wp->flags |= WEBS_POST_DATA;
445
                        done++;
446
                        break;
447
 
448
                default:
449
                        websError(wp, 404, T("Bad state"));
450
                        done++;
451
                        break;
452
                }
453
        }
454
        if (text) {
455
                bfree(B_L, text);
456
        }
457
}
458
 
459
/******************************************************************************/
460
/*
461
 *      Get input from the browser. Return TRUE (!0) if the request has been
462
 *      handled. Return -1 on errors, 1 if input read, and 0 to instruct the
463
 *      caller to call again for more input.
464
 *
465
 *      Note: socketRead will Return the number of bytes read if successful. This
466
 *      may be less than the requested "bufsize" and may be zero. It returns -1 for
467
 *      errors. It returns 0 for EOF. Otherwise it returns the number of bytes
468
 *      read. Since this may be zero, callers should use socketEof() to
469
 *      distinguish between this and EOF.
470
 */
471
 
472
static int websGetInput(webs_t wp, char_t **ptext, int *pnbytes)
473
{
474
        char_t  *text;
475
        char    buf[WEBS_SOCKET_BUFSIZ+1];
476
        int             nbytes, len, clen;
477
 
478
        a_assert(websValid(wp));
479
        a_assert(ptext);
480
        a_assert(pnbytes);
481
 
482
        *ptext = text = NULL;
483
        *pnbytes = 0;
484
 
485
/*
486
 *      If this request is a POST with a content length, we know the number
487
 *      of bytes to read so we use socketRead().
488
 */
489
        if (wp->state == WEBS_POST_CLEN) {
490
                len = (wp->clen > WEBS_SOCKET_BUFSIZ) ? WEBS_SOCKET_BUFSIZ : wp->clen;
491
        } else {
492
                len = 0;
493
        }
494
 
495
        if (len > 0) {
496
                nbytes = socketRead(wp->sid, buf, len);
497
 
498
                if (nbytes < 0) {                                                /* Error */
499
                        websDone(wp, 0);
500
                        return -1;
501
 
502
                }  else if (nbytes == 0) {                               /* EOF or No data available */
503
                        return -1;
504
 
505
                } else {                                                                /* Valid data */
506
/*
507
 *                      Convert to UNICODE if necessary.  First be sure the string
508
 *                      is NULL terminated.
509
 */
510
                        buf[nbytes] = '\0';
511
                        if ((text = ballocAscToUni(buf)) == NULL) {
512
                                websError(wp, 503, T("Insufficient memory"));
513
                                return -1;
514
                        }
515
                }
516
 
517
        } else {
518
                nbytes = socketGets(wp->sid, &text);
519
 
520
                if (nbytes < 0) {
521
/*
522
 *                      Error, EOF or incomplete
523
 */
524
                        if (socketEof(wp->sid)) {
525
/*
526
 *                              If this is a post request without content length, process
527
 *                              the request as we now have all the data. Otherwise just
528
 *                              close the connection.
529
 */
530
                                if (wp->state == WEBS_POST) {
531
                                        websUrlHandlerRequest(wp);
532
                                } else {
533
                                        websDone(wp, 0);
534
                                }
535
                        }
536
/*
537
 *                      If state is WEBS_HEADER and the ringq is empty, then this is a
538
 *                      simple request with no additional header fields to process and
539
 *                      no empty line terminator.
540
 */
541
                        if (wp->state == WEBS_HEADER && ringqLen(&wp->header) <= 0) {
542
                                websParseRequest(wp);
543
                                websUrlHandlerRequest(wp);
544
                        }
545
                        return -1;
546
 
547
                } else if (nbytes == 0) {
548
                        if (wp->state == WEBS_HEADER) {
549
/*
550
 *                              Valid empty line, now finished with header
551
 */
552
                                websParseRequest(wp);
553
                                if (wp->flags & WEBS_POST_REQUEST) {
554
                                        if (wp->flags & WEBS_CLEN) {
555
                                                wp->state = WEBS_POST_CLEN;
556
                                                clen = wp->clen;
557
                                        } else {
558
                                                wp->state = WEBS_POST;
559
                                                clen = 1;
560
                                        }
561
                                        if (clen > 0) {
562
                                                return 0;                                                        /* Get more data */
563
                                        }
564
                                        return 1;
565
 
566
                                }
567
/*
568
 *                              We've read the header so go and handle the request
569
 */
570
                                websUrlHandlerRequest(wp);
571
                        }
572
                        return -1;
573
 
574
                }
575
        }
576
        a_assert(text);
577
        a_assert(nbytes > 0);
578
        *ptext = text;
579
        *pnbytes = nbytes;
580
        return 1;
581
}
582
 
583
/******************************************************************************/
584
/*
585
 *      Parse the first line of a HTTP request
586
 */
587
 
588
static int websParseFirst(webs_t wp, char_t *text)
589
{
590
        char_t  *op, *proto, *url, *host, *query, *path, *port, *ext, *buf;
591
 
592
        a_assert(websValid(wp));
593
        a_assert(text && *text);
594
 
595
/*
596
 *      Determine the request type: GET, HEAD or POST
597
 */
598
        op = gstrtok(text, T(" \t"));
599
        if (op == NULL || *op == '\0') {
600
                websError(wp, 400, T("Bad HTTP request"));
601
                return -1;
602
        }
603
        if (gstrcmp(op, T("GET")) != 0) {
604
                if (gstrcmp(op, T("POST")) == 0) {
605
                        wp->flags |= WEBS_POST_REQUEST;
606
                } else if (gstrcmp(op, T("HEAD")) == 0) {
607
                        wp->flags |= WEBS_HEAD_REQUEST;
608
                } else {
609
                        websError(wp, 400, T("Bad request type"));
610
                        return -1;
611
                }
612
        }
613
 
614
/*
615
 *      Store result in the form (CGI) variable store
616
 */
617
        websSetVar(wp, T("REQUEST_METHOD"), op);
618
 
619
        url = gstrtok(NULL, T(" \t\n"));
620
        if (url == NULL || *url == '\0') {
621
                websError(wp, 400, T("Bad HTTP request"));
622
                return -1;
623
        }
624
 
625
/*
626
 *      Parse the URL and store all the various URL components. websUrlParse
627
 *      returns an allocated buffer in buf which we must free. We support both
628
 *      proxied and non-proxied requests. Proxied requests will have http://host/
629
 *      at the start of the URL. Non-proxied will just be local path names.
630
 */
631
        host = path = port = proto = query = ext = NULL;
632
        if (websUrlParse(url, &buf, &host, &path, &port, &query, &proto,
633
                        NULL, &ext) < 0) {
634
                websError(wp, 400, T("Bad URL format"));
635
                return -1;
636
        }
637
 
638
        wp->url = bstrdup(B_L, url);
639
        wp->query = bstrdup(B_L, query);
640
        wp->host = bstrdup(B_L, host);
641
        wp->path = bstrdup(B_L, path);
642
        wp->port = gatoi(port);
643
        if (gstrcmp(ext, T(".asp")) == 0) {
644
                wp->flags |= WEBS_ASP;
645
        }
646
        bfree(B_L, buf);
647
 
648
        websUrlType(url, wp->type, TSZ(wp->type));
649
 
650
#if WEBS_PROXY_SUPPORT
651
/*
652
 *      Determine if this is a request for local webs data. If it is not a proxied
653
 *      request from the browser, we won't see the "http://" or the system name, so
654
 *      we assume it must be talking to us directly for local webs data.
655
 *      Note: not fully implemented yet.
656
 */
657
        if (gstrstr(wp->url, T("http://")) == NULL ||
658
                ((gstrcmp(wp->host, T("localhost")) == 0 ||
659
                        gstrcmp(wp->host, websHost) == 0) && (wp->port == websPort))) {
660
                wp->flags |= WEBS_LOCAL_PAGE;
661
                if (gstrcmp(wp->path, T("/")) == 0) {
662
                        wp->flags |= WEBS_HOME_PAGE;
663
                }
664
        }
665
#endif
666
 
667
        ringqFlush(&wp->header);
668
        return 0;
669
}
670
 
671
/******************************************************************************/
672
/*
673
 *      Parse a full request
674
 */
675
 
676
static void websParseRequest(webs_t wp)
677
{
678
        char_t  *upperKey, *cp, *browser, *lp, *key, *value;
679
 
680
        a_assert(websValid(wp));
681
 
682
/*
683
 *      Define default CGI values
684
 */
685
        websSetVar(wp, T("HTTP_AUTHORIZATION"), T(""));
686
 
687
/*
688
 *      Parse the header and create the Http header keyword variables
689
 *      We rewrite the header as we go for non-local requests.  NOTE: this
690
 *      modifies the header string directly and tokenizes each line with '\0'.
691
 */
692
        browser = NULL;
693
        for (lp = (char_t*) wp->header.servp; lp && *lp; ) {
694
                cp = lp;
695
                if ((lp = gstrchr(lp, '\n')) != NULL) {
696
                        lp++;
697
                }
698
 
699
                if ((key = gstrtok(cp, T(": \t\n"))) == NULL) {
700
                        continue;
701
                }
702
 
703
                if ((value = gstrtok(NULL, T("\n"))) == NULL) {
704
                        value = T("");
705
                }
706
 
707
                while (gisspace(*value)) {
708
                        value++;
709
                }
710
                strlower(key);
711
 
712
/*
713
 *              Create a variable (CGI) for each line in the header
714
 */
715
                gsnprintf(&upperKey, (gstrlen(key) + 6), T("HTTP_%s"), key);
716
                for (cp = upperKey; *cp; cp++) {
717
                        if (*cp == '-')
718
                                *cp = '_';
719
                }
720
                strupper(upperKey);
721
                websSetVar(wp, upperKey, value);
722
                bfree(B_L, upperKey);
723
 
724
/*
725
 *              Track the requesting agent (browser) type
726
 */
727
                if (gstrcmp(key, T("user-agent")) == 0) {
728
                        wp->userAgent = bstrdup(B_L, value);
729
 
730
/*
731
 *              Parse the user authorization. ie. password
732
 */
733
                } else if (gstrcmp(key, T("authorization")) == 0) {
734
                        char_t  password[FNAMESIZE];
735
 
736
/*
737
 *                      The incoming value is password:username
738
 */
739
                        if ((cp = gstrchr(value, ' ')) != NULL) {
740
                                websDecode64(password, ++cp, sizeof(password));
741
                        } else {
742
                                websDecode64(password, value, sizeof(password));
743
                        }
744
                        if ((cp = gstrchr(password, ':')) != NULL) {
745
                                *cp++ = '\0';
746
                        }
747
                        if (cp) {
748
                                wp->password = bstrdup(B_L, cp);
749
                        } else {
750
                                wp->password = bstrdup(B_L, T(""));
751
                        }
752
 
753
/*
754
 *              Parse the content length
755
 */
756
                } else if (gstrcmp(key, T("content-length")) == 0) {
757
                        wp->flags |= WEBS_CLEN;
758
                        wp->clen = gatoi(value);
759
                        websSetVar(wp, T("CONTENT_LENGTH"), value);
760
 
761
#if WEBS_KEEP_ALIVE_SUPPORT
762
                } else if (gstrcmp(key, T("connection")) == 0) {
763
                        strlower(value);
764
                        if (gstrcmp(value, T("keep-alive")) == 0) {
765
                                wp->flags |= WEBS_KEEP_ALIVE;
766
                        }
767
#endif
768
 
769
#if WEBS_PROXY_SUPPORT
770
/*
771
 *              This may be useful if you wish to keep a local cache of web pages
772
 *              for proxied requests.
773
 */
774
                } else if (gstrcmp(key, T("pragma")) == 0) {
775
                        char_t  tmp[256];
776
                        gstrncpy(tmp, value, TSZ(tmp));
777
                        strlower(tmp);
778
                        if (gstrstr(tmp, T("no-cache"))) {
779
                                wp->flags |= WEBS_DONT_USE_CACHE;
780
                        }
781
#endif
782
 
783
/*
784
 *              Store the cookie
785
 */
786
                } else if (gstrcmp(key, T("cookie")) == 0) {
787
                        wp->flags |= WEBS_COOKIE;
788
                        wp->cookie = bstrdup(B_L, value);
789
 
790
#if WEBS_IF_MODIFIED_SUPPORT
791
/*
792
 *              See if the local page has been modified since the browser last
793
 *              requested this document. If not, just return a 302
794
 */
795
                } else if (gstrcmp(key, T("if-modified-since")) == 0) {
796
                        char_t *cmd;
797
                        time_t tip = 0;
798
 
799
                        if (cp = gstrchr(value, ';')) {
800
                                *cp = '\0';
801
                        }
802
 
803
                        if (cp = gstrstr(value, T(", "))) {
804
                                cp += 2;
805
                        }
806
 
807
                        if (gstrstr(cp, T("GMT"))) {
808
                                gsnprintf(&cmd, 64, T("clock scan %s -gmt 1"), cp);
809
                        } else {
810
                                gsnprintf(&cmd, 64, T("clock scan %s"), cp);
811
                        }
812
                        if (wp->since = dateParse(tip, cmd)) {
813
                                wp->flags |= WEBS_IF_MODIFIED;
814
                        }
815
                        bfreeSafe(B_L, cmd);
816
#endif
817
                }
818
        }
819
}
820
 
821
 
822
#if WEBS_IF_MODIFIED_SUPPORT
823
/******************************************************************************/
824
/*
825
 *              Parse the date and time string.
826
 */
827
 
828
static time_t dateParse(time_t tip, char_t *cmd)
829
{
830
        return (time_t)0;
831
}
832
#endif
833
 
834
 
835
/******************************************************************************/
836
/*
837
 *      Set the variable (CGI) environment for this request. Create variables
838
 *      for all standard CGI variables. Also decode the query string and create
839
 *      a variable for each name=value pair.
840
 */
841
 
842
void websSetEnv(webs_t wp)
843
{
844
        char_t  portBuf[8];
845
        char_t  *keyword, *value;
846
 
847
        a_assert(websValid(wp));
848
 
849
        websSetVar(wp, T("QUERY_STRING"), wp->query);
850
        websSetVar(wp, T("GATEWAY_INTERFACE"), T("CGI/1.1"));
851
        websSetVar(wp, T("SERVER_HOST"), websHost);
852
        websSetVar(wp, T("SERVER_URL"), websHostUrl);
853
        websSetVar(wp, T("REMOTE_HOST"), wp->ipaddr);
854
        websSetVar(wp, T("REMOTE_ADDR"), wp->ipaddr);
855
        websSetVar(wp, T("PATH_INFO"), wp->path);
856
        stritoa(websPort, portBuf, sizeof(portBuf));
857
        websSetVar(wp, T("SERVER_PORT"), portBuf);
858
 
859
/*
860
 *      Decode and create an environment query variable for each query keyword.
861
 *      We split into pairs at each '&', then split pairs at the '='.
862
 *      Note: we rely on wp->decodedQuery preserving the decoded values in the
863
 *      symbol table.
864
 */
865
        wp->decodedQuery = bstrdup(B_L, wp->query);
866
        keyword = gstrtok(wp->decodedQuery, T("&"));
867
        while (keyword != NULL) {
868
                if ((value = gstrchr(keyword, '=')) != NULL) {
869
                        *value++ = '\0';
870
                        websDecodeUrl(keyword, keyword, gstrlen(keyword));
871
                        websDecodeUrl(value, value, gstrlen(value));
872
 
873
                } else {
874
                        value = T("");
875
                }
876
 
877
                if (*keyword) {
878
                        websSetVar(wp, keyword, value);
879
                }
880
                keyword = gstrtok(NULL, T("&"));
881
        }
882
 
883
#if EMF
884
/*
885
 *      Add GoAhead Embedded Management Framework defines
886
 */
887
        websSetEmfEnvironment(wp);
888
#endif
889
}
890
 
891
/******************************************************************************/
892
/*
893
 *      Define a webs (CGI) variable for this connection. Also create in relevant
894
 *      scripting engines. Note: the incoming value may be volatile.
895
 */
896
 
897
void websSetVar(webs_t wp, char_t *var, char_t *value)
898
{
899
        value_t          v;
900
 
901
        a_assert(websValid(wp));
902
 
903
/*
904
 *      value_instring will allocate the string if required.
905
 */
906
        if (value) {
907
                v = valueString(value, VALUE_ALLOCATE);
908
        } else {
909
                v = valueString(T(""), VALUE_ALLOCATE);
910
        }
911
        symEnter(wp->cgiVars, var, v, 0);
912
}
913
 
914
/******************************************************************************/
915
/*
916
 *      Return TRUE if a webs variable exists for this connection.
917
 */
918
 
919
int websTestVar(webs_t wp, char_t *var)
920
{
921
        sym_t           *sp;
922
 
923
        a_assert(websValid(wp));
924
 
925
        if (var == NULL || *var == '\0') {
926
                return 0;
927
        }
928
 
929
        if ((sp = symLookup(wp->cgiVars, var)) == NULL) {
930
                return 0;
931
        }
932
        return 1;
933
}
934
 
935
/******************************************************************************/
936
/*
937
 *      Get a webs variable but return a default value if string not found.
938
 *      Note, defaultGetValue can be NULL to permit testing existance.
939
 */
940
 
941
char_t *websGetVar(webs_t wp, char_t *var, char_t *defaultGetValue)
942
{
943
        sym_t   *sp;
944
 
945
        a_assert(websValid(wp));
946
        a_assert(var && *var);
947
 
948
        if ((sp = symLookup(wp->cgiVars, var)) != NULL) {
949
                a_assert(sp->content.type == string);
950
                if (sp->content.value.string) {
951
                        return sp->content.value.string;
952
                } else {
953
                        return T("");
954
                }
955
        }
956
        return defaultGetValue;
957
}
958
 
959
/******************************************************************************/
960
/*
961
 *      Cancel the request timeout. Note may be called multiple times.
962
 */
963
 
964
static void websTimeoutCancel(webs_t wp)
965
{
966
        a_assert(websValid(wp));
967
 
968
        if (wp->timeout) {
969
                emfDeleteTimer(wp->timeout);
970
                wp->timeout = NULL;
971
        }
972
}
973
 
974
/******************************************************************************/
975
/*
976
 *      Output a HTTP response back to the browser. If redirect is set to a
977
 *      URL, the browser will be sent to this location.
978
 */
979
 
980
void websResponse(webs_t wp, int code, char_t *message, char_t *redirect)
981
{
982
        char_t          *date;
983
 
984
        a_assert(websValid(wp));
985
 
986
/*
987
 *      IE3.0 needs no Keep Alive for some return codes.
988
 */
989
        wp->flags &= ~WEBS_KEEP_ALIVE;
990
 
991
/*
992
 *      Only output the header if a header has not already been output.
993
 */
994
        if ( !(wp->flags & WEBS_HEADER_DONE)) {
995
                wp->flags |= WEBS_HEADER_DONE;
996
                websWrite(wp, T("HTTP/1.0 %d %s\r\n"), code, websErrorMsg(code));
997
 
998
                /* by license terms the following line of code must
999
                 * not be modified.
1000
                 */
1001
                websWrite(wp, T("Server: GoAhead-Webs\r\n"));
1002
 
1003
                if (wp->flags & WEBS_KEEP_ALIVE) {
1004
                        websWrite(wp, T("Connection: keep-alive\r\n"));
1005
                }
1006
                websWrite(wp, T("Pragma: no-cache\r\nCache-Control: no-cache\r\n"));
1007
 
1008
                if ((date = websGetDateString(NULL)) != NULL) {
1009
                        websWrite(wp, T("Date: %s\r\n"), date);
1010
                        bfree(B_L, date);
1011
                }
1012
                websWrite(wp, T("Content-Type: text/html\r\n"));
1013
 
1014
/*
1015
 *              We don't do a string length here as the message may be multi-line.
1016
 *              Ie. <CR><LF> will count as only one and we will have a content-length
1017
 *              that is too short.
1018
 *
1019
 *              websWrite(wp, T("Content-Length: %s\r\n"), message);
1020
 */
1021
                if (redirect) {
1022
                        websWrite(wp, T("Location: %s\r\n"), redirect);
1023
                }
1024
                websWrite(wp, T("\r\n"));
1025
        }
1026
 
1027
        if (message && *message) {
1028
                websWrite(wp, T("%s\r\n"), message);
1029
        }
1030
        websDone(wp, code);
1031
}
1032
 
1033
/******************************************************************************/
1034
/*
1035
 *      Redirect the user to another webs page
1036
 */
1037
 
1038
void websRedirect(webs_t wp, char_t *url)
1039
{
1040
        char_t  *msgbuf, *urlbuf;
1041
 
1042
        a_assert(websValid(wp));
1043
        a_assert(url);
1044
 
1045
        websStats.redirects++;
1046
        msgbuf = urlbuf = NULL;
1047
 
1048
/*
1049
 *      Some browsers require a http://host qualified URL for redirection
1050
 */
1051
        if (gstrstr(url, T("http://")) == NULL) {
1052
                if (*url == '/') {
1053
                        url++;
1054
                }
1055
                gsnprintf(&urlbuf, WEBS_MAX_URL + 80, T("http://%s/%s"),
1056
                        websGetVar(wp, T("HTTP_HOST"),  websHostUrl), url);
1057
                url = urlbuf;
1058
        }
1059
 
1060
/*
1061
 *      Add human readable message for completeness. Should not be required.
1062
 */
1063
        gsnprintf(&msgbuf, WEBS_MAX_URL + 80,
1064
                T("<html><head></head><body>\r\n\
1065
                This document has moved to a new <a href=\"%s\">location</a>.\r\n\
1066
                Please update your documents to reflect the new location.\r\n\
1067
                </body></html>\r\n"), url);
1068
 
1069
        websResponse(wp, 302, msgbuf, url);
1070
 
1071
        bfreeSafe(B_L, msgbuf);
1072
        bfreeSafe(B_L, urlbuf);
1073
}
1074
 
1075
/******************************************************************************/
1076
/*
1077
 *      Output an error message and cleanup
1078
 */
1079
 
1080
void websError(webs_t wp, int code, char_t *fmt, ...)
1081
{
1082
        va_list         args;
1083
        char_t          *msg, *userMsg, *buf;
1084
 
1085
        a_assert(websValid(wp));
1086
        a_assert(fmt);
1087
 
1088
        websStats.errors++;
1089
 
1090
        va_start(args, fmt);
1091
        userMsg = NULL;
1092
        gvsnprintf(&userMsg, WEBS_BUFSIZE, fmt, args);
1093
        va_end(args);
1094
 
1095
        msg = T("<html><head><title>Document Error: %s</title></head>\r\n\
1096
                <body><h2>Access Error: %s</h2>\r\n\
1097
                when trying to obtain <b>%s</b><br><p>%s</p></body></html>\r\n");
1098
/*
1099
 *      Ensure we have plenty of room
1100
 */
1101
        buf = NULL;
1102
        gsnprintf(&buf, WEBS_BUFSIZE, msg, websErrorMsg(code),
1103
                websErrorMsg(code), wp->url, userMsg);
1104
 
1105
        websResponse(wp, code, buf, NULL);
1106
        bfreeSafe(B_L, buf);
1107
        bfreeSafe(B_L, userMsg);
1108
}
1109
 
1110
/******************************************************************************/
1111
/*
1112
 *      Return the error message for a given code
1113
 */
1114
 
1115
static char_t *websErrorMsg(int code)
1116
{
1117
        websErrorType*  ep;
1118
 
1119
        for (ep = websErrors; ep->code; ep++) {
1120
                if (code == ep->code) {
1121
                        return ep->msg;
1122
                }
1123
        }
1124
        a_assert(0);
1125
        return T("");
1126
}
1127
 
1128
/******************************************************************************/
1129
/*
1130
 *      Do formatted output to the browser. This is the public ASP and form
1131
 *      write procedure.
1132
 */
1133
 
1134
int websWrite(webs_t wp, char_t* fmt, ...)
1135
{
1136
        va_list          vargs;
1137
        char_t          *buf;
1138
        int                      rc;
1139
 
1140
        a_assert(websValid(wp));
1141
 
1142
        va_start(vargs, fmt);
1143
 
1144
        buf = NULL;
1145
        rc = 0;
1146
        if (gvsnprintf(&buf, WEBS_BUFSIZE, fmt, vargs) >= WEBS_BUFSIZE) {
1147
                goahead_trace(0, T("webs: websWrite lost data, buffer overflow\n"));
1148
        }
1149
        va_end(vargs);
1150
        a_assert(buf);
1151
        if (buf) {
1152
                rc = websWriteBlock(wp, buf, gstrlen(buf));
1153
                bfree(B_L, buf);
1154
        }
1155
        return rc;
1156
}
1157
 
1158
/******************************************************************************/
1159
/*
1160
 *      Write a block of data of length "nChars" to the user's browser. Public
1161
 *      write block procedure.  If unicode is turned on this function expects
1162
 *      buf to be a unicode string and it converts it to ASCII before writing.
1163
 *      See websWriteBlockData to always write binary or ASCII data with no
1164
 *      unicode conversion.  This returns the number of char_t's processed.
1165
 */
1166
 
1167
int websWriteBlock(webs_t wp, char_t *buf, int nChars)
1168
{
1169
#if ! UNICODE
1170
        return websWriteBlockData(wp, buf, nChars);
1171
#else
1172
        int             r;
1173
        char    *charBuf;
1174
 
1175
        a_assert(buf);
1176
        a_assert(nChars >= 0);
1177
 
1178
        if ((charBuf = ballocUniToAsc(buf, nChars)) == NULL) {
1179
                return -1;
1180
        }
1181
        r = websWriteBlockData(wp, charBuf, nChars);
1182
        bfree(B_L, charBuf);
1183
        return r;
1184
#endif
1185
}
1186
 
1187
/******************************************************************************/
1188
/*
1189
 *      Write a block of data of length "nChars" to the user's browser. Same as
1190
 *      websWriteBlock except that it expects straight ASCII or binary and does no
1191
 *      unicode conversion before writing the data.
1192
 *      This returns the number of chars processed.
1193
 */
1194
 
1195
int websWriteBlockData(webs_t wp, char *buf, int nChars)
1196
{
1197
        int             len, done;
1198
 
1199
        a_assert(wp);
1200
        a_assert(websValid(wp));
1201
        a_assert(buf);
1202
        a_assert(nChars >= 0);
1203
 
1204
        done = len = 0;
1205
        while (nChars > 0) {
1206
                if ((len = socketWrite(wp->sid, buf, nChars)) < 0) {
1207
                        return -1;
1208
                }
1209
/*
1210
 *              Block in flush if the last write could not take any more data
1211
 */
1212
                socketFlush(wp->sid, len == 0);
1213
                nChars -= len;
1214
                buf += len;
1215
                done += len;
1216
        }
1217
        return done;
1218
}
1219
 
1220
/******************************************************************************/
1221
/*
1222
 *      Decode a URL (or part thereof). Allows insitu decoding.
1223
 */
1224
 
1225
void websDecodeUrl(char_t *decoded, char_t *token, int len)
1226
{
1227
        char_t  *ip,  *op;
1228
        int             num, i, c;
1229
 
1230
        a_assert(decoded);
1231
        a_assert(token);
1232
        num = 0;
1233
 
1234
        op = decoded;
1235
        for (ip = token; *ip && len > 0; ip++, op++) {
1236
                if (*ip == '+') {
1237
                        *op = ' ';
1238
                } else if (*ip == '%' && gisxdigit(ip[1]) && gisxdigit(ip[2])) {
1239
 
1240
/*
1241
 *                      Convert %nn to a single character
1242
 */
1243
                        ip++;
1244
                        for (i = 0; i < 2; i++, ip++) {
1245
                                c = tolower(*ip);
1246
                                if (c >= 'a' && c <= 'f') {
1247
                                        num = (num * 16) + 10 + c - 'a';
1248
                                } else {
1249
                                        num = (num * 16) + c - '0';
1250
                                }
1251
                        }
1252
                        *op = (char_t) num;
1253
                        ip--;
1254
 
1255
                } else {
1256
                        *op = *ip;
1257
                }
1258
                len--;
1259
        }
1260
        *op = '\0';
1261
}
1262
 
1263
/******************************************************************************/
1264
#if WEBS_LOG_SUPPORT
1265
/*
1266
 *      Output a log message
1267
 */
1268
 
1269
static void websLog(webs_t wp, int code)
1270
{
1271
        char_t  *buf;
1272
        char    *abuf;
1273
        int             len;
1274
 
1275
        a_assert(websValid(wp));
1276
 
1277
        buf = NULL;
1278
        gsnprintf(&buf, WEBS_MAX_URL + 80, T("%d %s %d %d\n"), time(0),
1279
                wp->url, code, wp->written);
1280
        len = gstrlen(buf);
1281
        abuf = ballocUniToAsc(buf, len+1);
1282
        write(websLogFd, abuf, len);
1283
        bfreeSafe(B_L, buf);
1284
        bfreeSafe(B_L, abuf);
1285
}
1286
 
1287
#endif /* WEBS_LOG_SUPPORT */
1288
 
1289
/******************************************************************************/
1290
/*
1291
 *      Request timeout. The timeout triggers if we have not read any data from
1292
 *      the users browser in the last WEBS_TIMEOUT period. If we have heard from
1293
 *      the browser, simply re-issue the timeout.
1294
 */
1295
 
1296
static void websTimeout(long iwp)
1297
{
1298
        webs_t          wp;
1299
        int                     delay, tm;
1300
 
1301
        wp = (webs_t) iwp;
1302
        a_assert(websValid(wp));
1303
 
1304
        tm = websGetTimeSinceMark(wp) * 1000;
1305
        if (tm >= WEBS_TIMEOUT) {
1306
                websStats.timeouts++;
1307
                wp->timeout = NULL;
1308
                websDone(wp, 404);
1309
 
1310
        } else {
1311
                delay = WEBS_TIMEOUT - tm;
1312
                a_assert(delay > 0);
1313
                wp->timeout = emfCreateTimer(delay, websTimeout, (long) wp);
1314
        }
1315
}
1316
 
1317
/******************************************************************************/
1318
/*
1319
 *      Called when the request is done.
1320
 */
1321
 
1322
void websDone(webs_t wp, int code)
1323
{
1324
        a_assert(websValid(wp));
1325
 
1326
/*
1327
 *      Disable socket handler in case keep alive set.
1328
 */
1329
        socketDeleteHandler(wp->sid);
1330
 
1331
        if (code != 200) {
1332
                wp->flags &= ~WEBS_KEEP_ALIVE;
1333
        }
1334
 
1335
#if WEBS_PROXY_SUPPORT
1336
        if (! (wp->flags & WEBS_LOCAL_PAGE)) {
1337
                websStats.activeNetRequests--;
1338
        }
1339
#endif
1340
 
1341
#if WEBS_LOG_SUPPORT
1342
        if (! (wp->flags & WEBS_REQUEST_DONE)) {
1343
                websLog(wp, code);
1344
        }
1345
#endif
1346
 
1347
/*
1348
 *      Close any opened document by a handler
1349
 */
1350
        websPageClose(wp);
1351
 
1352
/*
1353
 *      If using Keep Alive (HTTP/1.1) we keep the socket open for a period
1354
 *      while waiting for another request on the socket.
1355
 */
1356
        if (wp->flags & WEBS_KEEP_ALIVE) {
1357
                if (socketFlush(wp->sid, 0) == 0) {
1358
                        wp->state = WEBS_BEGIN;
1359
                        wp->flags |= WEBS_REQUEST_DONE;
1360
                        if (wp->header.buf) {
1361
                                ringqFlush(&wp->header);
1362
                        }
1363
                        socketCreateHandler(wp->sid, SOCKET_READABLE, websSocketEvent,
1364
                                (int) wp);
1365
                        websTimeoutCancel(wp);
1366
                        wp->timeout = emfCreateTimer(WEBS_TIMEOUT, websTimeout, (long) wp);
1367
                        return;
1368
                }
1369
        } else {
1370
                websTimeoutCancel(wp);
1371
                socketCloseConnection(wp->sid);
1372
        }
1373
        websFree(wp);
1374
}
1375
 
1376
/******************************************************************************/
1377
/*
1378
 *      Allocate a new webs structure
1379
 */
1380
 
1381
static int websAlloc(int sid)
1382
{
1383
        webs_t          wp;
1384
        int                     wid;
1385
 
1386
/*
1387
 *      Allocate a new handle for this connection
1388
 */
1389
        if ((wid = hAllocEntry((void***) &webs, &websMax,
1390
                        sizeof(struct websRec))) < 0) {
1391
                return -1;
1392
        }
1393
        wp = webs[wid];
1394
 
1395
        wp->wid = wid;
1396
        wp->sid = sid;
1397
        wp->state = WEBS_BEGIN;
1398
        wp->docfd = -1;
1399
        wp->dir = NULL;
1400
 
1401
        ringqOpen(&wp->header, WEBS_HEADER_BUFINC, WEBS_MAX_HEADER);
1402
 
1403
/*
1404
 *      Create storage for the CGI variables. We supply the symbol tables for
1405
 *      both the CGI variables and for the global functions. The function table
1406
 *      is common to all webs instances (ie. all browsers)
1407
 */
1408
        wp->cgiVars = symOpen(64);
1409
 
1410
        return wid;
1411
}
1412
 
1413
/******************************************************************************/
1414
/*
1415
 *      Free a webs structure
1416
 */
1417
 
1418
static void websFree(webs_t wp)
1419
{
1420
        a_assert(websValid(wp));
1421
 
1422
        if (wp->path)
1423
                bfree(B_L, wp->path);
1424
        if (wp->url)
1425
                bfree(B_L, wp->url);
1426
        if (wp->host)
1427
                bfree(B_L, wp->host);
1428
        if (wp->lpath)
1429
                bfree(B_L, wp->lpath);
1430
        if (wp->query)
1431
                bfree(B_L, wp->query);
1432
        if (wp->decodedQuery)
1433
                bfree(B_L, wp->decodedQuery);
1434
        if (wp->password)
1435
                bfree(B_L, wp->password);
1436
        if (wp->userName)
1437
                bfree(B_L, wp->userName);
1438
        if (wp->cookie)
1439
                bfree(B_L, wp->cookie);
1440
        if (wp->userAgent)
1441
                bfree(B_L, wp->userAgent);
1442
        if (wp->dir)
1443
                bfree(B_L, wp->dir);
1444
 
1445
        symClose(wp->cgiVars, websFreeVar);
1446
 
1447
        if (wp->header.buf) {
1448
                ringqClose(&wp->header);
1449
        }
1450
 
1451
        websMax = hFree((void***) &webs, wp->wid);
1452
        bfree(B_L, wp);
1453
        a_assert(websMax >= 0);
1454
}
1455
 
1456
/******************************************************************************/
1457
/*
1458
 *      Callback from symClose. Free the variable.
1459
 */
1460
 
1461
static void websFreeVar(sym_t* sp)
1462
{
1463
        valueFree(&sp->content);
1464
}
1465
 
1466
/******************************************************************************/
1467
/*
1468
 *      Return the server address
1469
 */
1470
 
1471
char_t* websGetHost()
1472
{
1473
        return websHost;
1474
}
1475
 
1476
/******************************************************************************/
1477
/*
1478
 *      Return the server address
1479
 */
1480
 
1481
char_t* websGetHostUrl()
1482
{
1483
        return websHostUrl;
1484
}
1485
 
1486
/******************************************************************************/
1487
/*
1488
 *      Return the listen port
1489
 */
1490
 
1491
int websGetPort()
1492
{
1493
        return websPort;
1494
}
1495
 
1496
/******************************************************************************/
1497
/*
1498
 *      Get the number of bytes to write
1499
 */
1500
 
1501
int websGetRequestBytes(webs_t wp)
1502
{
1503
        a_assert(websValid(wp));
1504
 
1505
        return wp->numbytes;
1506
}
1507
 
1508
/******************************************************************************/
1509
/*
1510
 *      Get the directory for this request
1511
 */
1512
 
1513
char_t *websGetRequestDir(webs_t wp)
1514
{
1515
        a_assert(websValid(wp));
1516
 
1517
        if (wp->dir == NULL) {
1518
                return T("");
1519
        }
1520
 
1521
        return wp->dir;
1522
}
1523
 
1524
/******************************************************************************/
1525
/*
1526
 *      Get the flags for this request
1527
 */
1528
 
1529
int websGetRequestFlags(webs_t wp)
1530
{
1531
        a_assert(websValid(wp));
1532
 
1533
        return wp->flags;
1534
}
1535
 
1536
/******************************************************************************/
1537
/*
1538
 *      Return the IP address
1539
 */
1540
 
1541
char_t *websGetRequestIpaddr(webs_t wp)
1542
{
1543
        a_assert(websValid(wp));
1544
 
1545
        return wp->ipaddr;
1546
}
1547
 
1548
/******************************************************************************/
1549
/*
1550
 *      Set the local path for the request
1551
 */
1552
 
1553
char_t *websGetRequestLpath(webs_t wp)
1554
{
1555
        a_assert(websValid(wp));
1556
 
1557
#if WEBS_PAGE_ROM
1558
        return wp->path;
1559
#else
1560
        return wp->lpath;
1561
#endif
1562
}
1563
 
1564
/******************************************************************************/
1565
/*
1566
 *      Get the path for this request
1567
 */
1568
 
1569
char_t *websGetRequestPath(webs_t wp)
1570
{
1571
        a_assert(websValid(wp));
1572
 
1573
        if (wp->path == NULL) {
1574
                return T("");
1575
        }
1576
 
1577
        return wp->path;
1578
}
1579
 
1580
/******************************************************************************/
1581
/*
1582
 *      Return the password
1583
 */
1584
 
1585
char_t* websGetRequestPassword(webs_t wp)
1586
{
1587
        a_assert(websValid(wp));
1588
 
1589
        return wp->password;
1590
}
1591
 
1592
/******************************************************************************/
1593
/*
1594
 *      Return the request type
1595
 */
1596
 
1597
char_t* websGetRequestType(webs_t wp)
1598
{
1599
        a_assert(websValid(wp));
1600
 
1601
        return wp->type;
1602
}
1603
 
1604
/******************************************************************************/
1605
/*
1606
 *      Return the username
1607
 */
1608
 
1609
char_t* websGetRequestUserName(webs_t wp)
1610
{
1611
        a_assert(websValid(wp));
1612
 
1613
        return wp->userName;
1614
}
1615
 
1616
/******************************************************************************/
1617
/*
1618
 *      Get the number of bytes written
1619
 */
1620
 
1621
int websGetRequestWritten(webs_t wp)
1622
{
1623
        a_assert(websValid(wp));
1624
 
1625
        return wp->written;
1626
}
1627
 
1628
/******************************************************************************/
1629
/*
1630
 *      Set the hostname
1631
 */
1632
 
1633
void websSetHost(char_t *host)
1634
{
1635
        gstrncpy(websHost, host, TSZ(websHost));
1636
}
1637
 
1638
/******************************************************************************/
1639
/*
1640
 *      Set the host URL
1641
 */
1642
 
1643
void websSetHostUrl(char_t *url)
1644
{
1645
        a_assert(url && *url);
1646
 
1647
        bfreeSafe(B_L, websHostUrl);
1648
        websHostUrl = gstrdup(B_L, url);
1649
}
1650
 
1651
/******************************************************************************/
1652
/*
1653
 *      Set the IP address
1654
 */
1655
 
1656
void websSetIpaddr(char_t *ipaddr)
1657
{
1658
        a_assert(ipaddr && *ipaddr);
1659
 
1660
        gstrncpy(websIpaddr, ipaddr, TSZ(websIpaddr));
1661
}
1662
 
1663
/******************************************************************************/
1664
/*
1665
 *      Set the number of bytes to write
1666
 */
1667
 
1668
void websSetRequestBytes(webs_t wp, int bytes)
1669
{
1670
        a_assert(websValid(wp));
1671
        a_assert(bytes >= 0);
1672
 
1673
        wp->numbytes = bytes;
1674
}
1675
 
1676
/******************************************************************************/
1677
/*
1678
 *      Set the flags for this request
1679
 */
1680
 
1681
void websSetRequestFlags(webs_t wp, int flags)
1682
{
1683
        a_assert(websValid(wp));
1684
 
1685
        wp->flags = flags;
1686
}
1687
 
1688
/******************************************************************************/
1689
/*
1690
 *      Set the local path for the request
1691
 */
1692
 
1693
void websSetRequestLpath(webs_t wp, char_t *lpath)
1694
{
1695
        a_assert(websValid(wp));
1696
        a_assert(lpath && *lpath);
1697
 
1698
        if (wp->lpath) {
1699
                bfree(B_L, wp->lpath);
1700
        }
1701
        wp->lpath = bstrdup(B_L, lpath);
1702
        websSetVar(wp, T("PATH_TRANSLATED"), wp->lpath);
1703
}
1704
 
1705
/******************************************************************************/
1706
/*
1707
 *      Update the URL path and the directory containing the web page
1708
 */
1709
 
1710
void websSetRequestPath(webs_t wp, char_t *dir, char_t *path)
1711
{
1712
        char_t  *tmp;
1713
 
1714
        a_assert(websValid(wp));
1715
 
1716
        if (dir) {
1717
                tmp = wp->dir;
1718
                wp->dir = bstrdup(B_L, dir);
1719
                if (tmp) {
1720
                        bfree(B_L, tmp);
1721
                }
1722
        }
1723
        if (path) {
1724
                tmp = wp->path;
1725
                wp->path = bstrdup(B_L, path);
1726
                websSetVar(wp, T("PATH_INFO"), wp->path);
1727
                if (tmp) {
1728
                        bfree(B_L, tmp);
1729
                }
1730
        }
1731
}
1732
 
1733
/******************************************************************************/
1734
/*
1735
 *      Set the Write handler for this socket
1736
 */
1737
 
1738
void websSetRequestSocketHandler(webs_t wp, int mask, void (*fn)(webs_t wp))
1739
{
1740
        a_assert(websValid(wp));
1741
 
1742
        wp->writeSocket = fn;
1743
        socketCreateHandler(wp->sid, SOCKET_WRITABLE, websSocketEvent, (int) wp);
1744
}
1745
 
1746
/******************************************************************************/
1747
/*
1748
 *      Set the number of bytes written
1749
 */
1750
 
1751
void websSetRequestWritten(webs_t wp, int written)
1752
{
1753
        a_assert(websValid(wp));
1754
 
1755
        wp->written = written;
1756
}
1757
 
1758
/******************************************************************************/
1759
/*
1760
 *      Reurn true if the webs handle is valid
1761
 */
1762
 
1763
int websValid(webs_t wp)
1764
{
1765
        int             wid;
1766
 
1767
        for (wid = 0; wid < websMax; wid++) {
1768
                if (wp == webs[wid]) {
1769
                        return 1;
1770
                }
1771
        }
1772
        return 0;
1773
}
1774
 
1775
/******************************************************************************/
1776
/*
1777
 *      Close the document handle.
1778
 */
1779
 
1780
int websCloseFileHandle(webs_t wp)
1781
{
1782
        a_assert(websValid(wp));
1783
 
1784
#ifndef WEBS_PAGE_ROM
1785
        if (wp->docfd >= 0) {
1786
                close(wp->docfd);
1787
                wp->docfd = -1;
1788
        }
1789
#endif
1790
 
1791
        return 0;
1792
}
1793
 
1794
/******************************************************************************/
1795
/*
1796
 *      Build an ASCII time string.  If sbuf is NULL we use the current time,
1797
 *      else we use the last modified time of sbuf;
1798
 */
1799
 
1800
char_t* websGetDateString(websStatType* sbuf)
1801
{
1802
        char_t* cp;
1803
        char_t* r;
1804
        time_t  now;
1805
 
1806
        if (sbuf == NULL) {
1807
                time(&now);
1808
        } else {
1809
                now = sbuf->mtime;
1810
        }
1811
        if ((cp = gctime(&now)) != NULL) {
1812
                cp[gstrlen(cp) - 1] = '\0';
1813
                r = bstrdup(B_L, cp);
1814
                return r;
1815
        }
1816
        return NULL;
1817
}
1818
 
1819
/******************************************************************************/
1820
/*
1821
 *      Mark time. Set a timestamp so that, later, we can return the number of
1822
 *      seconds since we made the mark. Note that the mark my not be a
1823
 *      "real" time, but rather a relative marker.
1824
 */
1825
 
1826
static void websMarkTime(webs_t wp)
1827
{
1828
        wp->timestamp = time(0);
1829
}
1830
 
1831
/******************************************************************************/
1832
/*
1833
 *      Get the number of seconds since the last mark.
1834
 */
1835
 
1836
static int websGetTimeSinceMark(webs_t wp)
1837
{
1838
        return time(0) - wp->timestamp;
1839
}
1840
 
1841
/******************************************************************************/

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.