Ignore:
File:
1 edited

Legend:

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

    r0a549cc rae481e0  
    4646#include <net/socket.h>
    4747
    48 #include <arg_parse.h>
    49 #include <macros.h>
    5048#include <str.h>
    51 #include <str_error.h>
    52 
    53 #define NAME  "websrv"
    54 
    55 #define DEFAULT_PORT  8080
    56 #define BACKLOG_SIZE  3
    57 
    58 #define WEB_ROOT  "/data/web"
     49
     50#define PORT_NUMBER 8080
     51#define BACKLOG_SIZE 3
     52
     53#define WEB_ROOT "/data/web"
    5954
    6055/** Buffer for receiving the request. */
    61 #define BUFFER_SIZE  1024
    62 
    63 static uint16_t port = DEFAULT_PORT;
    64 
     56#define BUFFER_SIZE 1024
    6557static char rbuf[BUFFER_SIZE];
    66 static size_t rbuf_out;
    67 static size_t rbuf_in;
     58static size_t rbuf_out, rbuf_in;
    6859
    6960static char lbuf[BUFFER_SIZE + 1];
     
    7263static char fbuf[BUFFER_SIZE];
    7364
    74 /** Responses to send to client. */
    75 
    76 static const char *msg_ok =
     65/** Response to send to client. */
     66static const char *ok_msg =
    7767    "HTTP/1.0 200 OK\r\n"
    7868    "\r\n";
    7969
    80 static const char *msg_bad_request =
    81     "HTTP/1.0 400 Bad Request\r\n"
    82     "\r\n"
    83     "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n"
    84     "<html><head>\r\n"
    85     "<title>400 Bad Request</title>\r\n"
    86     "</head>\r\n"
    87     "<body>\r\n"
    88     "<h1>Bad Request</h1>\r\n"
    89     "<p>The requested URL has bad syntax.</p>\r\n"
    90     "</body>\r\n"
    91     "</html>\r\n";
    92 
    93 static const char *msg_not_found =
    94     "HTTP/1.0 404 Not Found\r\n"
    95     "\r\n"
    96     "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n"
    97     "<html><head>\r\n"
    98     "<title>404 Not Found</title>\r\n"
    99     "</head>\r\n"
    100     "<body>\r\n"
    101     "<h1>Not Found</h1>\r\n"
    102     "<p>The requested URL was not found on this server.</p>\r\n"
    103     "</body>\r\n"
    104     "</html>\r\n";
    105 
    106 static const char *msg_not_implemented =
    107     "HTTP/1.0 501 Not Implemented\r\n"
    108     "\r\n"
    109     "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n"
    110     "<html><head>\r\n"
    111     "<title>501 Not Implemented</title>\r\n"
    112     "</head>\r\n"
    113     "<body>\r\n"
    114     "<h1>Not Implemented</h1>\r\n"
    115     "<p>The requested method is not implemented on this server.</p>\r\n"
    116     "</body>\r\n"
    117     "</html>\r\n";
    118 
    11970/** Receive one character (with buffering) */
    12071static int recv_char(int fd, char *c)
    12172{
     73        ssize_t rc;
     74
    12275        if (rbuf_out == rbuf_in) {
    12376                rbuf_out = 0;
    12477                rbuf_in = 0;
    125                
    126                 ssize_t rc = recv(fd, rbuf, BUFFER_SIZE, 0);
     78
     79                rc = recv(fd, rbuf, BUFFER_SIZE, 0);
    12780                if (rc <= 0) {
    128                         fprintf(stderr, "recv() failed (%zd)\n", rc);
     81                        printf("recv() failed (%zd)\n", rc);
    12982                        return rc;
    13083                }
    131                
     84
    13285                rbuf_in = rc;
    13386        }
    134        
     87
    13588        *c = rbuf[rbuf_out++];
    13689        return EOK;
    13790}
    13891
    139 /** Receive one line with length limit */
     92/** Receive one line with length limit. */
    14093static int recv_line(int fd)
    14194{
    142         char *bp = lbuf;
    143         char c = '\0';
    144        
     95        char c, prev;
     96        int rc;
     97        char *bp;
     98
     99        bp = lbuf; c = '\0';
    145100        while (bp < lbuf + BUFFER_SIZE) {
    146                 char prev = c;
    147                 int rc = recv_char(fd, &c);
    148                
     101                prev = c;
     102                rc = recv_char(fd, &c);
    149103                if (rc != EOK)
    150104                        return rc;
    151                
     105
    152106                *bp++ = c;
    153                 if ((prev == '\r') && (c == '\n'))
     107                if (prev == '\r' && c == '\n')
    154108                        break;
    155109        }
    156        
     110
    157111        lbuf_used = bp - lbuf;
    158112        *bp = '\0';
    159        
     113
    160114        if (bp == lbuf + BUFFER_SIZE)
    161115                return ELIMIT;
    162        
     116
    163117        return EOK;
    164118}
     
    166120static bool uri_is_valid(char *uri)
    167121{
     122        char *cp;
     123        char c;
     124
    168125        if (uri[0] != '/')
    169126                return false;
    170        
    171127        if (uri[1] == '.')
    172128                return false;
    173        
    174         char *cp = uri + 1;
    175        
     129
     130        cp = uri + 1;
    176131        while (*cp != '\0') {
    177                 char c = *cp++;
     132                c = *cp++;
    178133                if (c == '/')
    179134                        return false;
    180135        }
    181        
     136
    182137        return true;
    183138}
     
    185140static int send_response(int conn_sd, const char *msg)
    186141{
    187         size_t response_size = str_size(msg);
    188        
    189         fprintf(stderr, "Sending response\n");
    190         ssize_t rc = send(conn_sd, (void *) msg, response_size, 0);
     142        size_t response_size;
     143        ssize_t rc;
     144
     145        response_size = str_size(msg);
     146
     147        /* Send a canned response. */
     148        printf("Send response...\n");
     149        rc = send(conn_sd, (void *) msg, response_size, 0);
    191150        if (rc < 0) {
    192                 fprintf(stderr, "send() failed\n");
     151                printf("send() failed.\n");
    193152                return rc;
    194153        }
    195        
     154
    196155        return EOK;
    197156}
     
    199158static int uri_get(const char *uri, int conn_sd)
    200159{
     160        int rc;
     161        char *fname;
     162        int fd;
     163        ssize_t nr;
     164
    201165        if (str_cmp(uri, "/") == 0)
    202166                uri = "/index.htm";
    203        
    204         char *fname;
    205         int rc = asprintf(&fname, "%s%s", WEB_ROOT, uri);
     167
     168        rc = asprintf(&fname, "%s%s", WEB_ROOT, uri);
    206169        if (rc < 0)
    207170                return ENOMEM;
    208        
    209         int fd = open(fname, O_RDONLY);
     171
     172        fd = open(fname, O_RDONLY);
    210173        if (fd < 0) {
    211                 rc = send_response(conn_sd, msg_not_found);
     174                printf("File '%s' not found.\n", fname);
    212175                free(fname);
    213                 return rc;
    214         }
    215        
     176                return ENOENT;
     177        }
     178
    216179        free(fname);
    217        
    218         rc = send_response(conn_sd, msg_ok);
     180
     181        rc = send_response(conn_sd, ok_msg);
    219182        if (rc != EOK)
    220183                return rc;
    221        
     184
    222185        while (true) {
    223                 ssize_t nr = read(fd, fbuf, BUFFER_SIZE);
     186                nr = read(fd, fbuf, BUFFER_SIZE);
    224187                if (nr == 0)
    225188                        break;
    226                
     189
    227190                if (nr < 0) {
    228191                        close(fd);
    229192                        return EIO;
    230193                }
    231                
     194
    232195                rc = send(conn_sd, fbuf, nr, 0);
    233196                if (rc < 0) {
    234                         fprintf(stderr, "send() failed\n");
     197                        printf("send() failed\n");
    235198                        close(fd);
    236199                        return rc;
    237200                }
    238201        }
    239        
     202
    240203        close(fd);
    241        
     204
    242205        return EOK;
    243206}
     
    245208static int req_process(int conn_sd)
    246209{
    247         int rc = recv_line(conn_sd);
     210        int rc;
     211        char *uri, *end_uri;
     212
     213        rc = recv_line(conn_sd);
    248214        if (rc != EOK) {
    249                 fprintf(stderr, "recv_line() failed\n");
     215                printf("recv_line() failed\n");
    250216                return rc;
    251217        }
    252        
    253         fprintf(stderr, "Request: %s", lbuf);
    254        
     218
     219        printf("%s", lbuf);
     220
    255221        if (str_lcmp(lbuf, "GET ", 4) != 0) {
    256                 rc = send_response(conn_sd, msg_not_implemented);
    257                 return rc;
    258         }
    259        
    260         char *uri = lbuf + 4;
    261         char *end_uri = str_chr(uri, ' ');
     222                printf("Invalid HTTP method.\n");
     223                return EINVAL;
     224        }
     225
     226        uri = lbuf + 4;
     227        end_uri = str_chr(uri, ' ');
    262228        if (end_uri == NULL) {
    263229                end_uri = lbuf + lbuf_used - 2;
    264230                assert(*end_uri == '\r');
    265231        }
    266        
     232
    267233        *end_uri = '\0';
    268         fprintf(stderr, "Requested URI: %s\n", uri);
    269        
     234        printf("Requested URI '%s'.\n", uri);
     235
    270236        if (!uri_is_valid(uri)) {
    271                 rc = send_response(conn_sd, msg_bad_request);
    272                 return rc;
    273         }
    274        
     237                printf("Invalid request URI.\n");
     238                return EINVAL;
     239        }
     240
    275241        return uri_get(uri, conn_sd);
    276242}
    277243
    278 static void usage(void)
    279 {
    280         printf("Skeletal server\n"
    281             "\n"
    282             "Usage: " NAME " [options]\n"
    283             "\n"
    284             "Where options are:\n"
    285             "-p port_number | --port=port_number\n"
    286             "\tListening port (default " STRING(DEFAULT_PORT) ").\n"
    287             "\n"
    288             "-h | --help\n"
    289             "\tShow this application help.\n");
    290 }
    291 
    292 static int parse_option(int argc, char *argv[], int *index)
    293 {
    294         int value;
     244int main(int argc, char *argv[])
     245{
     246        struct sockaddr_in addr;
     247        struct sockaddr_in raddr;
     248
     249        socklen_t raddr_len;
     250
     251        int listen_sd, conn_sd;
    295252        int rc;
    296        
    297         switch (argv[*index][1]) {
    298         case 'h':
    299                 usage();
    300                 exit(0);
    301                 break;
    302         case 'p':
    303                 rc = arg_parse_int(argc, argv, index, &value, 0);
    304                 if (rc != EOK)
    305                         return rc;
    306                
    307                 port = (uint16_t) value;
    308                 break;
    309         /* Long options with double dash */
    310         case '-':
    311                 if (str_lcmp(argv[*index] + 2, "help", 5) == 0) {
    312                         usage();
    313                         exit(0);
    314                 } else if (str_lcmp(argv[*index] + 2, "port=", 5) == 0) {
    315                         rc = arg_parse_int(argc, argv, index, &value, 7);
    316                         if (rc != EOK)
    317                                 return rc;
    318                        
    319                         port = (uint16_t) value;
    320                 } else {
    321                         usage();
    322                         return EINVAL;
    323                 }
    324                 break;
    325         default:
    326                 usage();
    327                 return EINVAL;
    328         }
    329        
    330         return EOK;
    331 }
    332 
    333 int main(int argc, char *argv[])
    334 {
    335         /* Parse command line arguments */
    336         for (int i = 1; i < argc; i++) {
    337                 if (argv[i][0] == '-') {
    338                         int rc = parse_option(argc, argv, &i);
    339                         if (rc != EOK)
    340                                 return rc;
    341                 } else {
    342                         usage();
    343                         return EINVAL;
    344                 }
    345         }
    346        
    347         struct sockaddr_in addr;
    348        
     253
     254
    349255        addr.sin_family = AF_INET;
    350         addr.sin_port = htons(port);
    351        
    352         int rc = inet_pton(AF_INET, "127.0.0.1", (void *)
    353             &addr.sin_addr.s_addr);
     256        addr.sin_port = htons(PORT_NUMBER);
     257
     258        rc = inet_pton(AF_INET, "127.0.0.1", (void *) &addr.sin_addr.s_addr);
    354259        if (rc != EOK) {
    355                 fprintf(stderr, "Error parsing network address (%s)\n",
    356                     str_error(rc));
     260                printf("Error parsing network address.\n");
    357261                return 1;
    358262        }
    359        
    360         fprintf(stderr, "Creating socket\n");
    361        
    362         int listen_sd = socket(PF_INET, SOCK_STREAM, 0);
     263
     264        printf("Creating socket.\n");
     265
     266        listen_sd = socket(PF_INET, SOCK_STREAM, 0);
    363267        if (listen_sd < 0) {
    364                 fprintf(stderr, "Error creating listening socket (%s)\n",
    365                     str_error(listen_sd));
    366                 return 2;
    367         }
    368        
     268                printf("Error creating listening socket.\n");
     269                return 1;
     270        }
     271
    369272        rc = bind(listen_sd, (struct sockaddr *) &addr, sizeof(addr));
    370273        if (rc != EOK) {
    371                 fprintf(stderr, "Error binding socket (%s)\n",
    372                     str_error(rc));
    373                 return 3;
    374         }
    375        
     274                printf("Error binding socket.\n");
     275                return 1;
     276        }
     277
    376278        rc = listen(listen_sd, BACKLOG_SIZE);
    377279        if (rc != EOK) {
    378                 fprintf(stderr, "listen() failed (%s)\n", str_error(rc));
    379                 return 4;
    380         }
    381        
    382         fprintf(stderr, "Listening for connections at port %" PRIu16 "\n",
    383             port);
     280                printf("Error calling listen() (%d).\n", rc);
     281                return 1;
     282        }
     283
     284        printf("Listening for connections at port number %u.\n", PORT_NUMBER);
    384285        while (true) {
    385                 struct sockaddr_in raddr;
    386                 socklen_t raddr_len = sizeof(raddr);
    387                 int conn_sd = accept(listen_sd, (struct sockaddr *) &raddr,
     286                raddr_len = sizeof(raddr);
     287                conn_sd = accept(listen_sd, (struct sockaddr *) &raddr,
    388288                    &raddr_len);
    389                
     289
    390290                if (conn_sd < 0) {
    391                         fprintf(stderr, "accept() failed (%s)\n", str_error(rc));
     291                        printf("accept() failed.\n");
    392292                        continue;
    393293                }
    394                
    395                 fprintf(stderr, "Connection accepted (sd=%d), "
    396                     "waiting for request\n", conn_sd);
    397                
    398                 rbuf_out = 0;
    399                 rbuf_in = 0;
    400                
     294
     295                printf("Accepted connection, sd=%d.\n", conn_sd);
     296
     297                printf("Wait for client request\n");
     298                rbuf_out = rbuf_in = 0;
     299
    401300                rc = req_process(conn_sd);
    402                 if (rc != EOK)
    403                         fprintf(stderr, "Error processing request (%s)\n",
    404                             str_error(rc));
    405                
     301                if (rc != EOK)
     302                        printf("Error processing request.\n");
     303
    406304                rc = closesocket(conn_sd);
    407305                if (rc != EOK) {
    408                         fprintf(stderr, "Error closing connection socket (%s)\n",
    409                             str_error(rc));
     306                        printf("Error closing connection socket: %d\n", rc);
    410307                        closesocket(listen_sd);
    411                         return 5;
    412                 }
    413                
    414                 fprintf(stderr, "Connection closed\n");
    415         }
    416        
    417         /* Not reached */
     308                        return 1;
     309                }
     310
     311                printf("Closed connection.\n");
     312        }
     313
     314        /* Not reached. */
    418315        return 0;
    419316}
Note: See TracChangeset for help on using the changeset viewer.