Ignore:
File:
1 edited

Legend:

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

    r0a549cc r415578ef  
    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
     52#define WEB_ROOT "/data/web"
    5953
    6054/** Buffer for receiving the request. */
    61 #define BUFFER_SIZE  1024
    62 
    63 static uint16_t port = DEFAULT_PORT;
    64 
     55#define BUFFER_SIZE 1024
    6556static char rbuf[BUFFER_SIZE];
    66 static size_t rbuf_out;
    67 static size_t rbuf_in;
     57static size_t rbuf_out, rbuf_in;
    6858
    6959static char lbuf[BUFFER_SIZE + 1];
     
    7262static char fbuf[BUFFER_SIZE];
    7363
    74 /** Responses to send to client. */
    75 
    76 static const char *msg_ok =
     64/** Response to send to client. */
     65static const char *ok_msg =
    7766    "HTTP/1.0 200 OK\r\n"
    7867    "\r\n";
    7968
    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 
    11969/** Receive one character (with buffering) */
    12070static int recv_char(int fd, char *c)
    12171{
     72        ssize_t rc;
     73
    12274        if (rbuf_out == rbuf_in) {
    12375                rbuf_out = 0;
    12476                rbuf_in = 0;
    125                
    126                 ssize_t rc = recv(fd, rbuf, BUFFER_SIZE, 0);
     77
     78                rc = recv(fd, rbuf, BUFFER_SIZE, 0);
    12779                if (rc <= 0) {
    128                         fprintf(stderr, "recv() failed (%zd)\n", rc);
     80                        printf("recv() failed (%zd)\n", rc);
    12981                        return rc;
    13082                }
    131                
     83
    13284                rbuf_in = rc;
    13385        }
    134        
     86
    13587        *c = rbuf[rbuf_out++];
    13688        return EOK;
    13789}
    13890
    139 /** Receive one line with length limit */
     91/** Receive one line with length limit. */
    14092static int recv_line(int fd)
    14193{
    142         char *bp = lbuf;
    143         char c = '\0';
    144        
     94        char c, prev;
     95        int rc;
     96        char *bp;
     97
     98        bp = lbuf; c = '\0';
    14599        while (bp < lbuf + BUFFER_SIZE) {
    146                 char prev = c;
    147                 int rc = recv_char(fd, &c);
    148                
     100                prev = c;
     101                rc = recv_char(fd, &c);
    149102                if (rc != EOK)
    150103                        return rc;
    151                
     104
    152105                *bp++ = c;
    153                 if ((prev == '\r') && (c == '\n'))
     106                if (prev == '\r' && c == '\n')
    154107                        break;
    155108        }
    156        
     109
    157110        lbuf_used = bp - lbuf;
    158111        *bp = '\0';
    159        
     112
    160113        if (bp == lbuf + BUFFER_SIZE)
    161114                return ELIMIT;
    162        
     115
    163116        return EOK;
    164117}
     
    166119static bool uri_is_valid(char *uri)
    167120{
     121        char *cp;
     122        char c;
     123
    168124        if (uri[0] != '/')
    169125                return false;
    170        
    171126        if (uri[1] == '.')
    172127                return false;
    173        
    174         char *cp = uri + 1;
    175        
     128
     129        cp = uri + 1;
    176130        while (*cp != '\0') {
    177                 char c = *cp++;
     131                c = *cp++;
    178132                if (c == '/')
    179133                        return false;
    180134        }
    181        
     135
    182136        return true;
    183137}
     
    185139static int send_response(int conn_sd, const char *msg)
    186140{
    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);
     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);
    191149        if (rc < 0) {
    192                 fprintf(stderr, "send() failed\n");
     150                printf("send() failed.\n");
    193151                return rc;
    194152        }
    195        
     153
    196154        return EOK;
    197155}
     
    199157static int uri_get(const char *uri, int conn_sd)
    200158{
     159        int rc;
     160        char *fname;
     161        int fd;
     162        ssize_t nr;
     163
    201164        if (str_cmp(uri, "/") == 0)
    202165                uri = "/index.htm";
    203        
    204         char *fname;
    205         int rc = asprintf(&fname, "%s%s", WEB_ROOT, uri);
     166
     167        rc = asprintf(&fname, "%s%s", WEB_ROOT, uri);
    206168        if (rc < 0)
    207169                return ENOMEM;
    208        
    209         int fd = open(fname, O_RDONLY);
     170
     171        fd = open(fname, O_RDONLY);
    210172        if (fd < 0) {
    211                 rc = send_response(conn_sd, msg_not_found);
     173                printf("File '%s' not found.\n", fname);
    212174                free(fname);
    213                 return rc;
    214         }
    215        
     175                return ENOENT;
     176        }
     177
    216178        free(fname);
    217        
    218         rc = send_response(conn_sd, msg_ok);
     179
     180        rc = send_response(conn_sd, ok_msg);
    219181        if (rc != EOK)
    220182                return rc;
    221        
     183
    222184        while (true) {
    223                 ssize_t nr = read(fd, fbuf, BUFFER_SIZE);
     185                nr = read(fd, fbuf, BUFFER_SIZE);
    224186                if (nr == 0)
    225187                        break;
    226                
     188
    227189                if (nr < 0) {
    228190                        close(fd);
    229191                        return EIO;
    230192                }
    231                
     193
    232194                rc = send(conn_sd, fbuf, nr, 0);
    233195                if (rc < 0) {
    234                         fprintf(stderr, "send() failed\n");
     196                        printf("send() failed\n");
    235197                        close(fd);
    236198                        return rc;
    237199                }
    238200        }
    239        
     201
    240202        close(fd);
    241        
     203
    242204        return EOK;
    243205}
     
    245207static int req_process(int conn_sd)
    246208{
    247         int rc = recv_line(conn_sd);
     209        int rc;
     210        char *uri, *end_uri;
     211
     212        rc = recv_line(conn_sd);
    248213        if (rc != EOK) {
    249                 fprintf(stderr, "recv_line() failed\n");
     214                printf("recv_line() failed\n");
    250215                return rc;
    251216        }
    252        
    253         fprintf(stderr, "Request: %s", lbuf);
    254        
     217
     218        printf("%s", lbuf);
     219
    255220        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, ' ');
     221                printf("Invalid HTTP method.\n");
     222                return EINVAL;
     223        }
     224
     225        uri = lbuf + 4;
     226        end_uri = str_chr(uri, ' ');
    262227        if (end_uri == NULL) {
    263228                end_uri = lbuf + lbuf_used - 2;
    264229                assert(*end_uri == '\r');
    265230        }
    266        
     231
    267232        *end_uri = '\0';
    268         fprintf(stderr, "Requested URI: %s\n", uri);
    269        
     233        printf("Requested URI '%s'.\n", uri);
     234
    270235        if (!uri_is_valid(uri)) {
    271                 rc = send_response(conn_sd, msg_bad_request);
    272                 return rc;
    273         }
    274        
     236                printf("Invalid request URI.\n");
     237                return EINVAL;
     238        }
     239
    275240        return uri_get(uri, conn_sd);
    276241}
    277242
    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;
     243int main(int argc, char *argv[])
     244{
     245        struct sockaddr_in addr;
     246        struct sockaddr_in raddr;
     247
     248        socklen_t raddr_len;
     249
     250        int listen_sd, conn_sd;
    295251        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        
     252
     253
    349254        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);
     255        addr.sin_port = htons(PORT_NUMBER);
     256
     257        rc = inet_pton(AF_INET, "127.0.0.1", (void *) &addr.sin_addr.s_addr);
    354258        if (rc != EOK) {
    355                 fprintf(stderr, "Error parsing network address (%s)\n",
    356                     str_error(rc));
     259                printf("Error parsing network address.\n");
    357260                return 1;
    358261        }
    359        
    360         fprintf(stderr, "Creating socket\n");
    361        
    362         int listen_sd = socket(PF_INET, SOCK_STREAM, 0);
     262
     263        printf("Creating socket.\n");
     264
     265        listen_sd = socket(PF_INET, SOCK_STREAM, 0);
    363266        if (listen_sd < 0) {
    364                 fprintf(stderr, "Error creating listening socket (%s)\n",
    365                     str_error(listen_sd));
    366                 return 2;
    367         }
    368        
     267                printf("Error creating listening socket.\n");
     268                return 1;
     269        }
     270
    369271        rc = bind(listen_sd, (struct sockaddr *) &addr, sizeof(addr));
    370272        if (rc != EOK) {
    371                 fprintf(stderr, "Error binding socket (%s)\n",
    372                     str_error(rc));
    373                 return 3;
    374         }
    375        
    376         rc = listen(listen_sd, BACKLOG_SIZE);
     273                printf("Error binding socket.\n");
     274                return 1;
     275        }
     276
     277        rc = listen(listen_sd, 1);
    377278        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);
     279                printf("Error calling listen() (%d).\n", rc);
     280                return 1;
     281        }
     282
     283        printf("Listening for connections at port number %u.\n", PORT_NUMBER);
    384284        while (true) {
    385                 struct sockaddr_in raddr;
    386                 socklen_t raddr_len = sizeof(raddr);
    387                 int conn_sd = accept(listen_sd, (struct sockaddr *) &raddr,
     285                raddr_len = sizeof(raddr);
     286                conn_sd = accept(listen_sd, (struct sockaddr *) &raddr,
    388287                    &raddr_len);
    389                
     288
    390289                if (conn_sd < 0) {
    391                         fprintf(stderr, "accept() failed (%s)\n", str_error(rc));
     290                        printf("accept() failed.\n");
    392291                        continue;
    393292                }
    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                
     293
     294                printf("Accepted connection, sd=%d.\n", conn_sd);
     295
     296                printf("Wait for client request\n");
     297                rbuf_out = rbuf_in = 0;
     298
    401299                rc = req_process(conn_sd);
    402                 if (rc != EOK)
    403                         fprintf(stderr, "Error processing request (%s)\n",
    404                             str_error(rc));
    405                
     300                if (rc != EOK)
     301                        printf("Error processing request.\n");
     302
    406303                rc = closesocket(conn_sd);
    407304                if (rc != EOK) {
    408                         fprintf(stderr, "Error closing connection socket (%s)\n",
    409                             str_error(rc));
     305                        printf("Error closing connection socket: %d\n", rc);
    410306                        closesocket(listen_sd);
    411                         return 5;
    412                 }
    413                
    414                 fprintf(stderr, "Connection closed\n");
    415         }
    416        
    417         /* Not reached */
     307                        return 1;
     308                }
     309
     310                printf("Closed connection.\n");
     311        }
     312
     313        /* Not reached. */
    418314        return 0;
    419315}
Note: See TracChangeset for help on using the changeset viewer.