Changeset 4a4cc150 in mainline


Ignore:
Timestamp:
2011-12-10T22:32:55Z (12 years ago)
Author:
Jiri Svoboda <jiri@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
9c3bba0
Parents:
b5eae30
Message:

Improve web server to serve actual files from /data/web.

Location:
uspace
Files:
3 added
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/app/websrv/websrv.c

    rb5eae30 r4a4cc150  
    11/*
    2  * Copyright (c) 2010 Jiri Svoboda
     2 * Copyright (c) 2011 Jiri Svoboda
    33 * All rights reserved.
    44 *
     
    3131 */
    3232/**
    33  * @file (Less-than-skeleton) web server.
     33 * @file Skeletal web server.
    3434 */
    3535
     36#include <bool.h>
     37#include <errno.h>
    3638#include <stdio.h>
     39#include <sys/types.h>
     40#include <sys/stat.h>
     41#include <fcntl.h>
    3742
    3843#include <net/in.h>
     
    4449#define PORT_NUMBER 8080
    4550
     51#define WEB_ROOT "/data/web"
     52
    4653/** Buffer for receiving the request. */
    4754#define BUFFER_SIZE 1024
    48 static char buf[BUFFER_SIZE];
     55static char rbuf[BUFFER_SIZE];
     56static size_t rbuf_out, rbuf_in;
     57
     58static char lbuf[BUFFER_SIZE + 1];
     59static size_t lbuf_used;
     60
     61static char fbuf[BUFFER_SIZE];
    4962
    5063/** Response to send to client. */
    51 static const char *response_msg =
     64static const char *ok_msg =
    5265    "HTTP/1.0 200 OK\r\n"
    53     "\r\n"
    54     "<h1>Hello from HelenOS!</h1>\r\n";
     66    "\r\n";
     67
     68/** Receive one character (with buffering) */
     69static int recv_char(int fd, char *c)
     70{
     71        ssize_t rc;
     72
     73        if (rbuf_out == rbuf_in) {
     74                rbuf_out = 0;
     75                rbuf_in = 0;
     76
     77                rc = recv(fd, rbuf, BUFFER_SIZE, 0);
     78                if (rc <= 0) {
     79                        printf("recv() failed (%zd)\n", rc);
     80                        return rc;
     81                }
     82
     83                rbuf_in = rc;
     84        }
     85
     86        *c = rbuf[rbuf_out++];
     87        return EOK;
     88}
     89
     90/** Receive one line with length limit. */
     91static int recv_line(int fd)
     92{
     93        char c, prev;
     94        int rc;
     95        char *bp;
     96
     97        bp = lbuf; c = '\0';
     98        while (bp < lbuf + BUFFER_SIZE) {
     99                prev = c;
     100                rc = recv_char(fd, &c);
     101                if (rc != EOK)
     102                        return rc;
     103
     104                *bp++ = c;
     105                if (prev == '\r' && c == '\n')
     106                        break;
     107        }
     108
     109        lbuf_used = bp - lbuf;
     110        *bp = '\0';
     111
     112        if (bp == lbuf + BUFFER_SIZE)
     113                return ELIMIT;
     114
     115        return EOK;
     116}
     117
     118static bool uri_is_valid(char *uri)
     119{
     120        char *cp;
     121        char c;
     122
     123        if (uri[0] != '/')
     124                return false;
     125        if (uri[1] == '.')
     126                return false;
     127
     128        cp = uri + 1;
     129        while (*cp != '\0') {
     130                c = *cp++;
     131                if (c == '/')
     132                        return false;
     133        }
     134
     135        return true;
     136}
     137
     138static int send_response(int conn_sd, const char *msg)
     139{
     140        size_t response_size;
     141        ssize_t rc;
     142
     143        response_size = str_size(msg);
     144
     145        /* Send a canned response. */
     146        printf("Send response...\n");
     147        rc = send(conn_sd, (void *) msg, response_size, 0);
     148        if (rc < 0) {
     149                printf("send() failed.\n");
     150                return rc;
     151        }
     152
     153        return EOK;
     154}
     155
     156static int uri_get(const char *uri, int conn_sd)
     157{
     158        int rc;
     159        char *fname;
     160        int fd;
     161        ssize_t nr;
     162
     163        if (str_cmp(uri, "/") == 0)
     164                uri = "/index.htm";
     165
     166        rc = asprintf(&fname, "%s%s", WEB_ROOT, uri);
     167        if (rc < 0)
     168                return ENOMEM;
     169
     170        fd = open(fname, O_RDONLY);
     171        if (fd < 0) {
     172                printf("File '%s' not found.\n", fname);
     173                return ENOENT;
     174        }
     175
     176        rc = send_response(conn_sd, ok_msg);
     177        if (rc != EOK)
     178                return rc;
     179
     180        while (true) {
     181                nr = read(fd, fbuf, BUFFER_SIZE);
     182                if (nr == 0)
     183                        break;
     184
     185                if (nr < 0) {
     186                        close(fd);
     187                        return EIO;
     188                }
     189
     190                rc = send(conn_sd, fbuf, nr, 0);
     191                if (rc < 0) {
     192                        printf("send() failed\n");
     193                        close(fd);
     194                        return rc;
     195                }
     196        }
     197
     198        close(fd);
     199
     200        return EOK;
     201}
     202
     203static int req_process(int conn_sd)
     204{
     205        int rc;
     206        char *uri, *end_uri;
     207
     208        rc = recv_line(conn_sd);
     209        if (rc != EOK) {
     210                printf("recv_line() failed\n");
     211                return rc;
     212        }
     213
     214        printf("%s", lbuf);
     215
     216        if (str_lcmp(lbuf, "GET ", 4) != 0) {
     217                printf("Invalid HTTP method.\n");
     218                return EINVAL;
     219        }
     220
     221        uri = lbuf + 4;
     222        end_uri = str_chr(uri, ' ');
     223        if (end_uri == NULL) {
     224                end_uri = lbuf + lbuf_used - 2;
     225                assert(*end_uri == '\r');
     226        }
     227
     228        *end_uri = '\0';
     229        printf("Requested URI '%s'.\n", uri);
     230
     231        if (!uri_is_valid(uri)) {
     232                printf("Invalid request URI.\n");
     233                return EINVAL;
     234        }
     235
     236        return uri_get(uri, conn_sd);
     237}
    55238
    56239int main(int argc, char *argv[])
     
    64247        int rc;
    65248
    66         size_t response_size;
    67249
    68250        addr.sin_family = AF_INET;
     
    94276                return 1;
    95277        }
    96 
    97         response_size = str_size(response_msg);
    98278
    99279        printf("Listening for connections at port number %u.\n", PORT_NUMBER);
     
    105285                if (conn_sd < 0) {
    106286                        printf("accept() failed.\n");
    107                         return 1;
     287                        continue;
    108288                }
    109289
     
    111291
    112292                printf("Wait for client request\n");
    113 
    114                 /* Really we should wait for a blank line. */
    115                 rc = recv(conn_sd, buf, BUFFER_SIZE, 0);
    116                 if (rc < 0) {
    117                         printf("recv() failed\n");
    118                         return 1;
    119                 }
    120 
    121                 /* Send a canned response. */
    122                 printf("Send response...\n");
    123                 rc = send(conn_sd, (void *) response_msg, response_size, 0);
    124                 if (rc < 0) {
    125                         printf("send() failed.\n");
    126                         return 1;
    127                 }
     293                rbuf_out = rbuf_in = 0;
     294
     295                rc = req_process(conn_sd);
     296                if (rc != EOK)
     297                        printf("Error processing request.\n");
    128298
    129299                rc = closesocket(conn_sd);
Note: See TracChangeset for help on using the changeset viewer.