Changes in uspace/app/websrv/websrv.c [3e67ab1:f4a2d624] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/app/websrv/websrv.c
r3e67ab1 rf4a2d624 1 1 /* 2 * Copyright (c) 201 2Jiri Svoboda2 * Copyright (c) 2010 Jiri Svoboda 3 3 * All rights reserved. 4 4 * … … 31 31 */ 32 32 /** 33 * @file Skeletalweb server.33 * @file (Less-than-skeleton) web server. 34 34 */ 35 35 36 #include <bool.h>37 #include <errno.h>38 36 #include <stdio.h> 39 #include <sys/types.h>40 #include <sys/stat.h>41 #include <stdlib.h>42 #include <fcntl.h>43 #include <task.h>44 37 45 38 #include <net/in.h> … … 47 40 #include <net/socket.h> 48 41 49 #include <arg_parse.h>50 #include <macros.h>51 42 #include <str.h> 52 #include <str_error.h>53 43 54 #define NAME "websrv" 55 56 #define DEFAULT_PORT 8080 57 #define BACKLOG_SIZE 3 58 59 #define WEB_ROOT "/data/web" 44 #define PORT_NUMBER 8080 60 45 61 46 /** Buffer for receiving the request. */ 62 #define BUFFER_SIZE 1024 47 #define BUFFER_SIZE 1024 48 static char buf[BUFFER_SIZE]; 63 49 64 static uint16_t port = DEFAULT_PORT; 65 66 static char rbuf[BUFFER_SIZE]; 67 static size_t rbuf_out; 68 static size_t rbuf_in; 69 70 static char lbuf[BUFFER_SIZE + 1]; 71 static size_t lbuf_used; 72 73 static char fbuf[BUFFER_SIZE]; 74 75 static bool verbose = false; 76 77 /** Responses to send to client. */ 78 79 static const char *msg_ok = 50 /** Response to send to client. */ 51 static const char *response_msg = 80 52 "HTTP/1.0 200 OK\r\n" 81 "\r\n";82 83 static const char *msg_bad_request =84 "HTTP/1.0 400 Bad Request\r\n"85 53 "\r\n" 86 "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n" 87 "<html><head>\r\n" 88 "<title>400 Bad Request</title>\r\n" 89 "</head>\r\n" 90 "<body>\r\n" 91 "<h1>Bad Request</h1>\r\n" 92 "<p>The requested URL has bad syntax.</p>\r\n" 93 "</body>\r\n" 94 "</html>\r\n"; 95 96 static const char *msg_not_found = 97 "HTTP/1.0 404 Not Found\r\n" 98 "\r\n" 99 "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n" 100 "<html><head>\r\n" 101 "<title>404 Not Found</title>\r\n" 102 "</head>\r\n" 103 "<body>\r\n" 104 "<h1>Not Found</h1>\r\n" 105 "<p>The requested URL was not found on this server.</p>\r\n" 106 "</body>\r\n" 107 "</html>\r\n"; 108 109 static const char *msg_not_implemented = 110 "HTTP/1.0 501 Not Implemented\r\n" 111 "\r\n" 112 "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n" 113 "<html><head>\r\n" 114 "<title>501 Not Implemented</title>\r\n" 115 "</head>\r\n" 116 "<body>\r\n" 117 "<h1>Not Implemented</h1>\r\n" 118 "<p>The requested method is not implemented on this server.</p>\r\n" 119 "</body>\r\n" 120 "</html>\r\n"; 121 122 /** Receive one character (with buffering) */ 123 static int recv_char(int fd, char *c) 124 { 125 if (rbuf_out == rbuf_in) { 126 rbuf_out = 0; 127 rbuf_in = 0; 128 129 ssize_t rc = recv(fd, rbuf, BUFFER_SIZE, 0); 130 if (rc <= 0) { 131 fprintf(stderr, "recv() failed (%zd)\n", rc); 132 return rc; 133 } 134 135 rbuf_in = rc; 136 } 137 138 *c = rbuf[rbuf_out++]; 139 return EOK; 140 } 141 142 /** Receive one line with length limit */ 143 static int recv_line(int fd) 144 { 145 char *bp = lbuf; 146 char c = '\0'; 147 148 while (bp < lbuf + BUFFER_SIZE) { 149 char prev = c; 150 int rc = recv_char(fd, &c); 151 152 if (rc != EOK) 153 return rc; 154 155 *bp++ = c; 156 if ((prev == '\r') && (c == '\n')) 157 break; 158 } 159 160 lbuf_used = bp - lbuf; 161 *bp = '\0'; 162 163 if (bp == lbuf + BUFFER_SIZE) 164 return ELIMIT; 165 166 return EOK; 167 } 168 169 static bool uri_is_valid(char *uri) 170 { 171 if (uri[0] != '/') 172 return false; 173 174 if (uri[1] == '.') 175 return false; 176 177 char *cp = uri + 1; 178 179 while (*cp != '\0') { 180 char c = *cp++; 181 if (c == '/') 182 return false; 183 } 184 185 return true; 186 } 187 188 static int send_response(int conn_sd, const char *msg) 189 { 190 size_t response_size = str_size(msg); 191 192 if (verbose) 193 fprintf(stderr, "Sending response\n"); 194 195 ssize_t rc = send(conn_sd, (void *) msg, response_size, 0); 196 if (rc < 0) { 197 fprintf(stderr, "send() failed\n"); 198 return rc; 199 } 200 201 return EOK; 202 } 203 204 static int uri_get(const char *uri, int conn_sd) 205 { 206 if (str_cmp(uri, "/") == 0) 207 uri = "/index.html"; 208 209 char *fname; 210 int rc = asprintf(&fname, "%s%s", WEB_ROOT, uri); 211 if (rc < 0) 212 return ENOMEM; 213 214 int fd = open(fname, O_RDONLY); 215 if (fd < 0) { 216 rc = send_response(conn_sd, msg_not_found); 217 free(fname); 218 return rc; 219 } 220 221 free(fname); 222 223 rc = send_response(conn_sd, msg_ok); 224 if (rc != EOK) 225 return rc; 226 227 while (true) { 228 ssize_t nr = read(fd, fbuf, BUFFER_SIZE); 229 if (nr == 0) 230 break; 231 232 if (nr < 0) { 233 close(fd); 234 return EIO; 235 } 236 237 rc = send(conn_sd, fbuf, nr, 0); 238 if (rc < 0) { 239 fprintf(stderr, "send() failed\n"); 240 close(fd); 241 return rc; 242 } 243 } 244 245 close(fd); 246 247 return EOK; 248 } 249 250 static int req_process(int conn_sd) 251 { 252 int rc = recv_line(conn_sd); 253 if (rc != EOK) { 254 fprintf(stderr, "recv_line() failed\n"); 255 return rc; 256 } 257 258 if (verbose) 259 fprintf(stderr, "Request: %s", lbuf); 260 261 if (str_lcmp(lbuf, "GET ", 4) != 0) { 262 rc = send_response(conn_sd, msg_not_implemented); 263 return rc; 264 } 265 266 char *uri = lbuf + 4; 267 char *end_uri = str_chr(uri, ' '); 268 if (end_uri == NULL) { 269 end_uri = lbuf + lbuf_used - 2; 270 assert(*end_uri == '\r'); 271 } 272 273 *end_uri = '\0'; 274 if (verbose) 275 fprintf(stderr, "Requested URI: %s\n", uri); 276 277 if (!uri_is_valid(uri)) { 278 rc = send_response(conn_sd, msg_bad_request); 279 return rc; 280 } 281 282 return uri_get(uri, conn_sd); 283 } 284 285 static void usage(void) 286 { 287 printf("Skeletal server\n" 288 "\n" 289 "Usage: " NAME " [options]\n" 290 "\n" 291 "Where options are:\n" 292 "-p port_number | --port=port_number\n" 293 "\tListening port (default " STRING(DEFAULT_PORT) ").\n" 294 "\n" 295 "-h | --help\n" 296 "\tShow this application help.\n" 297 "-v | --verbose\n" 298 "\tVerbose mode\n"); 299 } 300 301 static int parse_option(int argc, char *argv[], int *index) 302 { 303 int value; 304 int rc; 305 306 switch (argv[*index][1]) { 307 case 'h': 308 usage(); 309 exit(0); 310 break; 311 case 'p': 312 rc = arg_parse_int(argc, argv, index, &value, 0); 313 if (rc != EOK) 314 return rc; 315 316 port = (uint16_t) value; 317 break; 318 case 'v': 319 verbose = true; 320 break; 321 /* Long options with double dash */ 322 case '-': 323 if (str_lcmp(argv[*index] + 2, "help", 5) == 0) { 324 usage(); 325 exit(0); 326 } else if (str_lcmp(argv[*index] + 2, "port=", 5) == 0) { 327 rc = arg_parse_int(argc, argv, index, &value, 7); 328 if (rc != EOK) 329 return rc; 330 331 port = (uint16_t) value; 332 } else if (str_cmp(argv[*index] +2, "verbose") == 0) { 333 verbose = true; 334 } else { 335 usage(); 336 return EINVAL; 337 } 338 break; 339 default: 340 usage(); 341 return EINVAL; 342 } 343 344 return EOK; 345 } 54 "<h1>Hello from HelenOS!</h1>\r\n"; 346 55 347 56 int main(int argc, char *argv[]) 348 57 { 349 /* Parse command line arguments */350 for (int i = 1; i < argc; i++) {351 if (argv[i][0] == '-') {352 int rc = parse_option(argc, argv, &i);353 if (rc != EOK)354 return rc;355 } else {356 usage();357 return EINVAL;358 }359 }360 361 58 struct sockaddr_in addr; 362 59 struct sockaddr_in raddr; 60 61 socklen_t raddr_len; 62 63 int listen_sd, conn_sd; 64 int rc; 65 66 size_t response_size; 67 363 68 addr.sin_family = AF_INET; 364 addr.sin_port = htons(port); 365 366 int rc = inet_pton(AF_INET, "127.0.0.1", (void *) 367 &addr.sin_addr.s_addr); 69 addr.sin_port = htons(PORT_NUMBER); 70 71 rc = inet_pton(AF_INET, "127.0.0.1", (void *) &addr.sin_addr.s_addr); 368 72 if (rc != EOK) { 369 fprintf(stderr, "Error parsing network address (%s)\n", 370 str_error(rc)); 73 printf("Error parsing network address.\n"); 371 74 return 1; 372 75 } 373 374 printf("%s: HelenOS web server\n", NAME);375 76 376 if (verbose) 377 fprintf(stderr, "Creating socket\n"); 378 379 int listen_sd = socket(PF_INET, SOCK_STREAM, 0); 77 printf("Creating socket.\n"); 78 79 listen_sd = socket(PF_INET, SOCK_STREAM, 0); 380 80 if (listen_sd < 0) { 381 fprintf(stderr, "Error creating listening socket (%s)\n", 382 str_error(listen_sd)); 383 return 2; 81 printf("Error creating listening socket.\n"); 82 return 1; 384 83 } 385 84 386 85 rc = bind(listen_sd, (struct sockaddr *) &addr, sizeof(addr)); 387 86 if (rc != EOK) { 388 fprintf(stderr, "Error binding socket (%s)\n", 389 str_error(rc)); 390 return 3; 87 printf("Error binding socket.\n"); 88 return 1; 391 89 } 392 393 rc = listen(listen_sd, BACKLOG_SIZE);90 91 rc = listen(listen_sd, 1); 394 92 if (rc != EOK) { 395 fprintf(stderr, "listen() failed (%s)\n", str_error(rc));396 return 4;93 printf("Error calling listen() (%d).\n", rc); 94 return 1; 397 95 } 398 399 fprintf(stderr, "%s: Listening for connections at port %" PRIu16 "\n",400 NAME, port);401 96 402 task_retval(0);97 response_size = str_size(response_msg); 403 98 99 printf("Listening for connections at port number %u.\n", PORT_NUMBER); 404 100 while (true) { 405 struct sockaddr_in raddr; 406 socklen_t raddr_len = sizeof(raddr); 407 int conn_sd = accept(listen_sd, (struct sockaddr *) &raddr, 101 raddr_len = sizeof(raddr); 102 conn_sd = accept(listen_sd, (struct sockaddr *) &raddr, 408 103 &raddr_len); 409 104 410 105 if (conn_sd < 0) { 411 fprintf(stderr, "accept() failed (%s)\n", str_error(rc));412 continue;106 printf("accept() failed.\n"); 107 return 1; 413 108 } 414 415 if (verbose) { 416 fprintf(stderr, "Connection accepted (sd=%d), " 417 "waiting for request\n", conn_sd); 109 110 printf("Accepted connection, sd=%d.\n", conn_sd); 111 112 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; 418 119 } 419 420 rbuf_out = 0;421 rbuf_in = 0;422 423 rc = req_process(conn_sd);424 if (rc != EOK)425 fprintf(stderr, "Error processing request (%s)\n",426 str_error(rc));427 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 } 128 428 129 rc = closesocket(conn_sd); 429 130 if (rc != EOK) { 430 fprintf(stderr, "Error closing connection socket (%s)\n", 431 str_error(rc)); 432 closesocket(listen_sd); 433 return 5; 131 printf("Error closing connection socket: %d\n", rc); 132 return 1; 434 133 } 435 436 if (verbose) 437 fprintf(stderr, "Connection closed\n"); 134 135 printf("Closed connection.\n"); 438 136 } 439 440 /* Not reached */137 138 /* Not reached. */ 441 139 return 0; 442 140 }
Note:
See TracChangeset
for help on using the changeset viewer.