Ignore:
File:
1 edited

Legend:

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

    r9c3bba0 rf4a2d624  
    11/*
    2  * Copyright (c) 2011 Jiri Svoboda
     2 * Copyright (c) 2010 Jiri Svoboda
    33 * All rights reserved.
    44 *
     
    3131 */
    3232/**
    33  * @file Skeletal web server.
     33 * @file (Less-than-skeleton) web server.
    3434 */
    3535
    36 #include <bool.h>
    37 #include <errno.h>
    3836#include <stdio.h>
    39 #include <sys/types.h>
    40 #include <sys/stat.h>
    41 #include <stdlib.h>
    42 #include <fcntl.h>
    4337
    4438#include <net/in.h>
     
    5044#define PORT_NUMBER 8080
    5145
    52 #define WEB_ROOT "/data/web"
    53 
    5446/** Buffer for receiving the request. */
    5547#define BUFFER_SIZE 1024
    56 static char rbuf[BUFFER_SIZE];
    57 static size_t rbuf_out, rbuf_in;
    58 
    59 static char lbuf[BUFFER_SIZE + 1];
    60 static size_t lbuf_used;
    61 
    62 static char fbuf[BUFFER_SIZE];
     48static char buf[BUFFER_SIZE];
    6349
    6450/** Response to send to client. */
    65 static const char *ok_msg =
     51static const char *response_msg =
    6652    "HTTP/1.0 200 OK\r\n"
    67     "\r\n";
    68 
    69 /** Receive one character (with buffering) */
    70 static 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. */
    92 static 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 
    119 static 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 
    139 static 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 
    157 static 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 
    207 static 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 }
     53    "\r\n"
     54    "<h1>Hello from HelenOS!</h1>\r\n";
    24255
    24356int main(int argc, char *argv[])
     
    25164        int rc;
    25265
     66        size_t response_size;
    25367
    25468        addr.sin_family = AF_INET;
     
    28195        }
    28296
     97        response_size = str_size(response_msg);
     98
    28399        printf("Listening for connections at port number %u.\n", PORT_NUMBER);
    284100        while (true) {
     
    289105                if (conn_sd < 0) {
    290106                        printf("accept() failed.\n");
    291                         continue;
     107                        return 1;
    292108                }
    293109
     
    295111
    296112                printf("Wait for client request\n");
    297                 rbuf_out = rbuf_in = 0;
    298113
    299                 rc = req_process(conn_sd);
    300                 if (rc != EOK)
    301                         printf("Error processing request.\n");
     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                }
    302128
    303129                rc = closesocket(conn_sd);
Note: See TracChangeset for help on using the changeset viewer.