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