Changes in uspace/app/websrv/websrv.c [415578ef:0a549cc] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/app/websrv/websrv.c
r415578ef r0a549cc 46 46 #include <net/socket.h> 47 47 48 #include <arg_parse.h> 49 #include <macros.h> 48 50 #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" 53 59 54 60 /** Buffer for receiving the request. */ 55 #define BUFFER_SIZE 1024 61 #define BUFFER_SIZE 1024 62 63 static uint16_t port = DEFAULT_PORT; 64 56 65 static char rbuf[BUFFER_SIZE]; 57 static size_t rbuf_out, rbuf_in; 66 static size_t rbuf_out; 67 static size_t rbuf_in; 58 68 59 69 static char lbuf[BUFFER_SIZE + 1]; … … 62 72 static char fbuf[BUFFER_SIZE]; 63 73 64 /** Response to send to client. */ 65 static const char *ok_msg = 74 /** Responses to send to client. */ 75 76 static const char *msg_ok = 66 77 "HTTP/1.0 200 OK\r\n" 67 78 "\r\n"; 68 79 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 69 119 /** Receive one character (with buffering) */ 70 120 static int recv_char(int fd, char *c) 71 121 { 72 ssize_t rc;73 74 122 if (rbuf_out == rbuf_in) { 75 123 rbuf_out = 0; 76 124 rbuf_in = 0; 77 78 rc = recv(fd, rbuf, BUFFER_SIZE, 0);125 126 ssize_t rc = recv(fd, rbuf, BUFFER_SIZE, 0); 79 127 if (rc <= 0) { 80 printf("recv() failed (%zd)\n", rc);128 fprintf(stderr, "recv() failed (%zd)\n", rc); 81 129 return rc; 82 130 } 83 131 84 132 rbuf_in = rc; 85 133 } 86 134 87 135 *c = rbuf[rbuf_out++]; 88 136 return EOK; 89 137 } 90 138 91 /** Receive one line with length limit .*/139 /** Receive one line with length limit */ 92 140 static int recv_line(int fd) 93 141 { 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 99 145 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 102 149 if (rc != EOK) 103 150 return rc; 104 151 105 152 *bp++ = c; 106 if ( prev == '\r' && c == '\n')153 if ((prev == '\r') && (c == '\n')) 107 154 break; 108 155 } 109 156 110 157 lbuf_used = bp - lbuf; 111 158 *bp = '\0'; 112 159 113 160 if (bp == lbuf + BUFFER_SIZE) 114 161 return ELIMIT; 115 162 116 163 return EOK; 117 164 } … … 119 166 static bool uri_is_valid(char *uri) 120 167 { 121 char *cp;122 char c;123 124 168 if (uri[0] != '/') 125 169 return false; 170 126 171 if (uri[1] == '.') 127 172 return false; 128 129 cp = uri + 1; 173 174 char *cp = uri + 1; 175 130 176 while (*cp != '\0') { 131 c = *cp++;177 char c = *cp++; 132 178 if (c == '/') 133 179 return false; 134 180 } 135 181 136 182 return true; 137 183 } … … 139 185 static int send_response(int conn_sd, const char *msg) 140 186 { 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); 149 191 if (rc < 0) { 150 printf("send() failed.\n");151 return rc; 152 } 153 192 fprintf(stderr, "send() failed\n"); 193 return rc; 194 } 195 154 196 return EOK; 155 197 } … … 157 199 static int uri_get(const char *uri, int conn_sd) 158 200 { 159 int rc;160 char *fname;161 int fd;162 ssize_t nr;163 164 201 if (str_cmp(uri, "/") == 0) 165 202 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); 168 206 if (rc < 0) 169 207 return ENOMEM; 170 171 fd = open(fname, O_RDONLY);208 209 int fd = open(fname, O_RDONLY); 172 210 if (fd < 0) { 173 printf("File '%s' not found.\n", fname);211 rc = send_response(conn_sd, msg_not_found); 174 212 free(fname); 175 return ENOENT;176 } 177 213 return rc; 214 } 215 178 216 free(fname); 179 180 rc = send_response(conn_sd, ok_msg);217 218 rc = send_response(conn_sd, msg_ok); 181 219 if (rc != EOK) 182 220 return rc; 183 221 184 222 while (true) { 185 nr = read(fd, fbuf, BUFFER_SIZE);223 ssize_t nr = read(fd, fbuf, BUFFER_SIZE); 186 224 if (nr == 0) 187 225 break; 188 226 189 227 if (nr < 0) { 190 228 close(fd); 191 229 return EIO; 192 230 } 193 231 194 232 rc = send(conn_sd, fbuf, nr, 0); 195 233 if (rc < 0) { 196 printf("send() failed\n");234 fprintf(stderr, "send() failed\n"); 197 235 close(fd); 198 236 return rc; 199 237 } 200 238 } 201 239 202 240 close(fd); 203 241 204 242 return EOK; 205 243 } … … 207 245 static int req_process(int conn_sd) 208 246 { 209 int rc; 210 char *uri, *end_uri; 211 212 rc = recv_line(conn_sd); 247 int rc = recv_line(conn_sd); 213 248 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 220 255 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, ' '); 227 262 if (end_uri == NULL) { 228 263 end_uri = lbuf + lbuf_used - 2; 229 264 assert(*end_uri == '\r'); 230 265 } 231 266 232 267 *end_uri = '\0'; 233 printf("Requested URI '%s'.\n", uri);234 268 fprintf(stderr, "Requested URI: %s\n", uri); 269 235 270 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 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; 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(); 237 327 return EINVAL; 238 328 } 239 240 return uri_get(uri, conn_sd);329 330 return EOK; 241 331 } 242 332 243 333 int main(int argc, char *argv[]) 244 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 245 347 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 254 349 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); 258 354 if (rc != EOK) { 259 printf("Error parsing network address.\n"); 355 fprintf(stderr, "Error parsing network address (%s)\n", 356 str_error(rc)); 260 357 return 1; 261 358 } 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); 266 363 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 271 369 rc = bind(listen_sd, (struct sockaddr *) &addr, sizeof(addr)); 272 370 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); 278 377 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); 284 384 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, 287 388 &raddr_len); 288 389 289 390 if (conn_sd < 0) { 290 printf("accept() failed.\n");391 fprintf(stderr, "accept() failed (%s)\n", str_error(rc)); 291 392 continue; 292 393 } 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 299 401 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 303 406 rc = closesocket(conn_sd); 304 407 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)); 306 410 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 */ 314 418 return 0; 315 419 }
Note:
See TracChangeset
for help on using the changeset viewer.