Ignore:
File:
1 edited

Legend:

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

    r415578ef r0a549cc  
    4646#include <net/socket.h>
    4747
     48#include <arg_parse.h>
     49#include <macros.h>
    4850#include <str.h>
    49 
    50 #define PORT_NUMBER 8080
    51 
    52 #define WEB_ROOT "/data/web"
     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"
    5359
    5460/** Buffer for receiving the request. */
    55 #define BUFFER_SIZE 1024
     61#define BUFFER_SIZE  1024
     62
     63static uint16_t port = DEFAULT_PORT;
     64
    5665static char rbuf[BUFFER_SIZE];
    57 static size_t rbuf_out, rbuf_in;
     66static size_t rbuf_out;
     67static size_t rbuf_in;
    5868
    5969static char lbuf[BUFFER_SIZE + 1];
     
    6272static char fbuf[BUFFER_SIZE];
    6373
    64 /** Response to send to client. */
    65 static const char *ok_msg =
     74/** Responses to send to client. */
     75
     76static const char *msg_ok =
    6677    "HTTP/1.0 200 OK\r\n"
    6778    "\r\n";
    6879
     80static 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
     93static 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
     106static 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
    69119/** Receive one character (with buffering) */
    70120static int recv_char(int fd, char *c)
    71121{
    72         ssize_t rc;
    73 
    74122        if (rbuf_out == rbuf_in) {
    75123                rbuf_out = 0;
    76124                rbuf_in = 0;
    77 
    78                 rc = recv(fd, rbuf, BUFFER_SIZE, 0);
     125               
     126                ssize_t rc = recv(fd, rbuf, BUFFER_SIZE, 0);
    79127                if (rc <= 0) {
    80                         printf("recv() failed (%zd)\n", rc);
     128                        fprintf(stderr, "recv() failed (%zd)\n", rc);
    81129                        return rc;
    82130                }
    83 
     131               
    84132                rbuf_in = rc;
    85133        }
    86 
     134       
    87135        *c = rbuf[rbuf_out++];
    88136        return EOK;
    89137}
    90138
    91 /** Receive one line with length limit. */
     139/** Receive one line with length limit */
    92140static int recv_line(int fd)
    93141{
    94         char c, prev;
    95         int rc;
    96         char *bp;
    97 
    98         bp = lbuf; c = '\0';
     142        char *bp = lbuf;
     143        char c = '\0';
     144       
    99145        while (bp < lbuf + BUFFER_SIZE) {
    100                 prev = c;
    101                 rc = recv_char(fd, &c);
     146                char prev = c;
     147                int rc = recv_char(fd, &c);
     148               
    102149                if (rc != EOK)
    103150                        return rc;
    104 
     151               
    105152                *bp++ = c;
    106                 if (prev == '\r' && c == '\n')
     153                if ((prev == '\r') && (c == '\n'))
    107154                        break;
    108155        }
    109 
     156       
    110157        lbuf_used = bp - lbuf;
    111158        *bp = '\0';
    112 
     159       
    113160        if (bp == lbuf + BUFFER_SIZE)
    114161                return ELIMIT;
    115 
     162       
    116163        return EOK;
    117164}
     
    119166static bool uri_is_valid(char *uri)
    120167{
    121         char *cp;
    122         char c;
    123 
    124168        if (uri[0] != '/')
    125169                return false;
     170       
    126171        if (uri[1] == '.')
    127172                return false;
    128 
    129         cp = uri + 1;
     173       
     174        char *cp = uri + 1;
     175       
    130176        while (*cp != '\0') {
    131                 c = *cp++;
     177                char c = *cp++;
    132178                if (c == '/')
    133179                        return false;
    134180        }
    135 
     181       
    136182        return true;
    137183}
     
    139185static int send_response(int conn_sd, const char *msg)
    140186{
    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);
     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);
    149191        if (rc < 0) {
    150                 printf("send() failed.\n");
    151                 return rc;
    152         }
    153 
     192                fprintf(stderr, "send() failed\n");
     193                return rc;
     194        }
     195       
    154196        return EOK;
    155197}
     
    157199static int uri_get(const char *uri, int conn_sd)
    158200{
    159         int rc;
    160         char *fname;
    161         int fd;
    162         ssize_t nr;
    163 
    164201        if (str_cmp(uri, "/") == 0)
    165202                uri = "/index.htm";
    166 
    167         rc = asprintf(&fname, "%s%s", WEB_ROOT, uri);
     203       
     204        char *fname;
     205        int rc = asprintf(&fname, "%s%s", WEB_ROOT, uri);
    168206        if (rc < 0)
    169207                return ENOMEM;
    170 
    171         fd = open(fname, O_RDONLY);
     208       
     209        int fd = open(fname, O_RDONLY);
    172210        if (fd < 0) {
    173                 printf("File '%s' not found.\n", fname);
     211                rc = send_response(conn_sd, msg_not_found);
    174212                free(fname);
    175                 return ENOENT;
    176         }
    177 
     213                return rc;
     214        }
     215       
    178216        free(fname);
    179 
    180         rc = send_response(conn_sd, ok_msg);
     217       
     218        rc = send_response(conn_sd, msg_ok);
    181219        if (rc != EOK)
    182220                return rc;
    183 
     221       
    184222        while (true) {
    185                 nr = read(fd, fbuf, BUFFER_SIZE);
     223                ssize_t nr = read(fd, fbuf, BUFFER_SIZE);
    186224                if (nr == 0)
    187225                        break;
    188 
     226               
    189227                if (nr < 0) {
    190228                        close(fd);
    191229                        return EIO;
    192230                }
    193 
     231               
    194232                rc = send(conn_sd, fbuf, nr, 0);
    195233                if (rc < 0) {
    196                         printf("send() failed\n");
     234                        fprintf(stderr, "send() failed\n");
    197235                        close(fd);
    198236                        return rc;
    199237                }
    200238        }
    201 
     239       
    202240        close(fd);
    203 
     241       
    204242        return EOK;
    205243}
     
    207245static int req_process(int conn_sd)
    208246{
    209         int rc;
    210         char *uri, *end_uri;
    211 
    212         rc = recv_line(conn_sd);
     247        int rc = recv_line(conn_sd);
    213248        if (rc != EOK) {
    214                 printf("recv_line() failed\n");
    215                 return rc;
    216         }
    217 
    218         printf("%s", lbuf);
    219 
     249                fprintf(stderr, "recv_line() failed\n");
     250                return rc;
     251        }
     252       
     253        fprintf(stderr, "Request: %s", lbuf);
     254       
    220255        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, ' ');
     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, ' ');
    227262        if (end_uri == NULL) {
    228263                end_uri = lbuf + lbuf_used - 2;
    229264                assert(*end_uri == '\r');
    230265        }
    231 
     266       
    232267        *end_uri = '\0';
    233         printf("Requested URI '%s'.\n", uri);
    234 
     268        fprintf(stderr, "Requested URI: %s\n", uri);
     269       
    235270        if (!uri_is_valid(uri)) {
    236                 printf("Invalid request URI.\n");
     271                rc = send_response(conn_sd, msg_bad_request);
     272                return rc;
     273        }
     274       
     275        return uri_get(uri, conn_sd);
     276}
     277
     278static 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
     292static int parse_option(int argc, char *argv[], int *index)
     293{
     294        int value;
     295        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();
    237327                return EINVAL;
    238328        }
    239 
    240         return uri_get(uri, conn_sd);
     329       
     330        return EOK;
    241331}
    242332
    243333int main(int argc, char *argv[])
    244334{
     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       
    245347        struct sockaddr_in addr;
    246         struct sockaddr_in raddr;
    247 
    248         socklen_t raddr_len;
    249 
    250         int listen_sd, conn_sd;
    251         int rc;
    252 
    253 
     348       
    254349        addr.sin_family = AF_INET;
    255         addr.sin_port = htons(PORT_NUMBER);
    256 
    257         rc = inet_pton(AF_INET, "127.0.0.1", (void *) &addr.sin_addr.s_addr);
     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);
    258354        if (rc != EOK) {
    259                 printf("Error parsing network address.\n");
     355                fprintf(stderr, "Error parsing network address (%s)\n",
     356                    str_error(rc));
    260357                return 1;
    261358        }
    262 
    263         printf("Creating socket.\n");
    264 
    265         listen_sd = socket(PF_INET, SOCK_STREAM, 0);
     359       
     360        fprintf(stderr, "Creating socket\n");
     361       
     362        int listen_sd = socket(PF_INET, SOCK_STREAM, 0);
    266363        if (listen_sd < 0) {
    267                 printf("Error creating listening socket.\n");
    268                 return 1;
    269         }
    270 
     364                fprintf(stderr, "Error creating listening socket (%s)\n",
     365                    str_error(listen_sd));
     366                return 2;
     367        }
     368       
    271369        rc = bind(listen_sd, (struct sockaddr *) &addr, sizeof(addr));
    272370        if (rc != EOK) {
    273                 printf("Error binding socket.\n");
    274                 return 1;
    275         }
    276 
    277         rc = listen(listen_sd, 1);
     371                fprintf(stderr, "Error binding socket (%s)\n",
     372                    str_error(rc));
     373                return 3;
     374        }
     375       
     376        rc = listen(listen_sd, BACKLOG_SIZE);
    278377        if (rc != EOK) {
    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);
     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);
    284384        while (true) {
    285                 raddr_len = sizeof(raddr);
    286                 conn_sd = accept(listen_sd, (struct sockaddr *) &raddr,
     385                struct sockaddr_in raddr;
     386                socklen_t raddr_len = sizeof(raddr);
     387                int conn_sd = accept(listen_sd, (struct sockaddr *) &raddr,
    287388                    &raddr_len);
    288 
     389               
    289390                if (conn_sd < 0) {
    290                         printf("accept() failed.\n");
     391                        fprintf(stderr, "accept() failed (%s)\n", str_error(rc));
    291392                        continue;
    292393                }
    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 
     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               
    299401                rc = req_process(conn_sd);
    300                 if (rc != EOK)
    301                         printf("Error processing request.\n");
    302 
     402                if (rc != EOK)
     403                        fprintf(stderr, "Error processing request (%s)\n",
     404                            str_error(rc));
     405               
    303406                rc = closesocket(conn_sd);
    304407                if (rc != EOK) {
    305                         printf("Error closing connection socket: %d\n", rc);
     408                        fprintf(stderr, "Error closing connection socket (%s)\n",
     409                            str_error(rc));
    306410                        closesocket(listen_sd);
    307                         return 1;
    308                 }
    309 
    310                 printf("Closed connection.\n");
    311         }
    312 
    313         /* Not reached. */
     411                        return 5;
     412                }
     413               
     414                fprintf(stderr, "Connection closed\n");
     415        }
     416       
     417        /* Not reached */
    314418        return 0;
    315419}
Note: See TracChangeset for help on using the changeset viewer.