Ignore:
File:
1 edited

Legend:

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

    rf4a2d624 r9c3bba0  
    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 <stdlib.h>
     42#include <fcntl.h>
    3743
    3844#include <net/in.h>
     
    4450#define PORT_NUMBER 8080
    4551
     52#define WEB_ROOT "/data/web"
     53
    4654/** Buffer for receiving the request. */
    4755#define BUFFER_SIZE 1024
    48 static char buf[BUFFER_SIZE];
     56static char rbuf[BUFFER_SIZE];
     57static size_t rbuf_out, rbuf_in;
     58
     59static char lbuf[BUFFER_SIZE + 1];
     60static size_t lbuf_used;
     61
     62static char fbuf[BUFFER_SIZE];
    4963
    5064/** Response to send to client. */
    51 static const char *response_msg =
     65static const char *ok_msg =
    5266    "HTTP/1.0 200 OK\r\n"
    53     "\r\n"
    54     "<h1>Hello from HelenOS!</h1>\r\n";
     67    "\r\n";
     68
     69/** Receive one character (with buffering) */
     70static int recv_char(int fd, char *c)
     71{
     72        ssize_t rc;
     73
     74        if (rbuf_out == rbuf_in) {
     75                rbuf_out = 0;
     76                rbuf_in = 0;
     77
     78                rc = recv(fd, rbuf, BUFFER_SIZE, 0);
     79                if (rc <= 0) {
     80                        printf("recv() failed (%zd)\n", rc);
     81                        return rc;
     82                }
     83
     84                rbuf_in = rc;
     85        }
     86
     87        *c = rbuf[rbuf_out++];
     88        return EOK;
     89}
     90
     91/** Receive one line with length limit. */
     92static int recv_line(int fd)
     93{
     94        char c, prev;
     95        int rc;
     96        char *bp;
     97
     98        bp = lbuf; c = '\0';
     99        while (bp < lbuf + BUFFER_SIZE) {
     100                prev = c;
     101                rc = recv_char(fd, &c);
     102                if (rc != EOK)
     103                        return rc;
     104
     105                *bp++ = c;
     106                if (prev == '\r' && c == '\n')
     107                        break;
     108        }
     109
     110        lbuf_used = bp - lbuf;
     111        *bp = '\0';
     112
     113        if (bp == lbuf + BUFFER_SIZE)
     114                return ELIMIT;
     115
     116        return EOK;
     117}
     118
     119static bool uri_is_valid(char *uri)
     120{
     121        char *cp;
     122        char c;
     123
     124        if (uri[0] != '/')
     125                return false;
     126        if (uri[1] == '.')
     127                return false;
     128
     129        cp = uri + 1;
     130        while (*cp != '\0') {
     131                c = *cp++;
     132                if (c == '/')
     133                        return false;
     134        }
     135
     136        return true;
     137}
     138
     139static int send_response(int conn_sd, const char *msg)
     140{
     141        size_t response_size;
     142        ssize_t rc;
     143
     144        response_size = str_size(msg);
     145
     146        /* Send a canned response. */
     147        printf("Send response...\n");
     148        rc = send(conn_sd, (void *) msg, response_size, 0);
     149        if (rc < 0) {
     150                printf("send() failed.\n");
     151                return rc;
     152        }
     153
     154        return EOK;
     155}
     156
     157static int uri_get(const char *uri, int conn_sd)
     158{
     159        int rc;
     160        char *fname;
     161        int fd;
     162        ssize_t nr;
     163
     164        if (str_cmp(uri, "/") == 0)
     165                uri = "/index.htm";
     166
     167        rc = asprintf(&fname, "%s%s", WEB_ROOT, uri);
     168        if (rc < 0)
     169                return ENOMEM;
     170
     171        fd = open(fname, O_RDONLY);
     172        if (fd < 0) {
     173                printf("File '%s' not found.\n", fname);
     174                free(fname);
     175                return ENOENT;
     176        }
     177
     178        free(fname);
     179
     180        rc = send_response(conn_sd, ok_msg);
     181        if (rc != EOK)
     182                return rc;
     183
     184        while (true) {
     185                nr = read(fd, fbuf, BUFFER_SIZE);
     186                if (nr == 0)
     187                        break;
     188
     189                if (nr < 0) {
     190                        close(fd);
     191                        return EIO;
     192                }
     193
     194                rc = send(conn_sd, fbuf, nr, 0);
     195                if (rc < 0) {
     196                        printf("send() failed\n");
     197                        close(fd);
     198                        return rc;
     199                }
     200        }
     201
     202        close(fd);
     203
     204        return EOK;
     205}
     206
     207static int req_process(int conn_sd)
     208{
     209        int rc;
     210        char *uri, *end_uri;
     211
     212        rc = recv_line(conn_sd);
     213        if (rc != EOK) {
     214                printf("recv_line() failed\n");
     215                return rc;
     216        }
     217
     218        printf("%s", lbuf);
     219
     220        if (str_lcmp(lbuf, "GET ", 4) != 0) {
     221                printf("Invalid HTTP method.\n");
     222                return EINVAL;
     223        }
     224
     225        uri = lbuf + 4;
     226        end_uri = str_chr(uri, ' ');
     227        if (end_uri == NULL) {
     228                end_uri = lbuf + lbuf_used - 2;
     229                assert(*end_uri == '\r');
     230        }
     231
     232        *end_uri = '\0';
     233        printf("Requested URI '%s'.\n", uri);
     234
     235        if (!uri_is_valid(uri)) {
     236                printf("Invalid request URI.\n");
     237                return EINVAL;
     238        }
     239
     240        return uri_get(uri, conn_sd);
     241}
    55242
    56243int main(int argc, char *argv[])
     
    64251        int rc;
    65252
    66         size_t response_size;
    67253
    68254        addr.sin_family = AF_INET;
     
    94280                return 1;
    95281        }
    96 
    97         response_size = str_size(response_msg);
    98282
    99283        printf("Listening for connections at port number %u.\n", PORT_NUMBER);
     
    105289                if (conn_sd < 0) {
    106290                        printf("accept() failed.\n");
    107                         return 1;
     291                        continue;
    108292                }
    109293
     
    111295
    112296                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                 }
     297                rbuf_out = rbuf_in = 0;
     298
     299                rc = req_process(conn_sd);
     300                if (rc != EOK)
     301                        printf("Error processing request.\n");
    128302
    129303                rc = closesocket(conn_sd);
Note: See TracChangeset for help on using the changeset viewer.