Changes in uspace/app/websrv/websrv.c [0a549cc:ae481e0] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/app/websrv/websrv.c
r0a549cc rae481e0 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 #define BACKLOG_SIZE 3 52 53 #define WEB_ROOT "/data/web" 59 54 60 55 /** Buffer for receiving the request. */ 61 #define BUFFER_SIZE 1024 62 63 static uint16_t port = DEFAULT_PORT; 64 56 #define BUFFER_SIZE 1024 65 57 static char rbuf[BUFFER_SIZE]; 66 static size_t rbuf_out; 67 static size_t rbuf_in; 58 static size_t rbuf_out, rbuf_in; 68 59 69 60 static char lbuf[BUFFER_SIZE + 1]; … … 72 63 static char fbuf[BUFFER_SIZE]; 73 64 74 /** Responses to send to client. */ 75 76 static const char *msg_ok = 65 /** Response to send to client. */ 66 static const char *ok_msg = 77 67 "HTTP/1.0 200 OK\r\n" 78 68 "\r\n"; 79 69 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 70 /** Receive one character (with buffering) */ 120 71 static int recv_char(int fd, char *c) 121 72 { 73 ssize_t rc; 74 122 75 if (rbuf_out == rbuf_in) { 123 76 rbuf_out = 0; 124 77 rbuf_in = 0; 125 126 ssize_trc = recv(fd, rbuf, BUFFER_SIZE, 0);78 79 rc = recv(fd, rbuf, BUFFER_SIZE, 0); 127 80 if (rc <= 0) { 128 fprintf(stderr,"recv() failed (%zd)\n", rc);81 printf("recv() failed (%zd)\n", rc); 129 82 return rc; 130 83 } 131 84 132 85 rbuf_in = rc; 133 86 } 134 87 135 88 *c = rbuf[rbuf_out++]; 136 89 return EOK; 137 90 } 138 91 139 /** Receive one line with length limit */92 /** Receive one line with length limit. */ 140 93 static int recv_line(int fd) 141 94 { 142 char *bp = lbuf; 143 char c = '\0'; 144 95 char c, prev; 96 int rc; 97 char *bp; 98 99 bp = lbuf; c = '\0'; 145 100 while (bp < lbuf + BUFFER_SIZE) { 146 char prev = c; 147 int rc = recv_char(fd, &c); 148 101 prev = c; 102 rc = recv_char(fd, &c); 149 103 if (rc != EOK) 150 104 return rc; 151 105 152 106 *bp++ = c; 153 if ( (prev == '\r') && (c == '\n'))107 if (prev == '\r' && c == '\n') 154 108 break; 155 109 } 156 110 157 111 lbuf_used = bp - lbuf; 158 112 *bp = '\0'; 159 113 160 114 if (bp == lbuf + BUFFER_SIZE) 161 115 return ELIMIT; 162 116 163 117 return EOK; 164 118 } … … 166 120 static bool uri_is_valid(char *uri) 167 121 { 122 char *cp; 123 char c; 124 168 125 if (uri[0] != '/') 169 126 return false; 170 171 127 if (uri[1] == '.') 172 128 return false; 173 174 char *cp = uri + 1; 175 129 130 cp = uri + 1; 176 131 while (*cp != '\0') { 177 c har c= *cp++;132 c = *cp++; 178 133 if (c == '/') 179 134 return false; 180 135 } 181 136 182 137 return true; 183 138 } … … 185 140 static int send_response(int conn_sd, const char *msg) 186 141 { 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); 142 size_t response_size; 143 ssize_t rc; 144 145 response_size = str_size(msg); 146 147 /* Send a canned response. */ 148 printf("Send response...\n"); 149 rc = send(conn_sd, (void *) msg, response_size, 0); 191 150 if (rc < 0) { 192 fprintf(stderr, "send() failed\n");151 printf("send() failed.\n"); 193 152 return rc; 194 153 } 195 154 196 155 return EOK; 197 156 } … … 199 158 static int uri_get(const char *uri, int conn_sd) 200 159 { 160 int rc; 161 char *fname; 162 int fd; 163 ssize_t nr; 164 201 165 if (str_cmp(uri, "/") == 0) 202 166 uri = "/index.htm"; 203 204 char *fname; 205 int rc = asprintf(&fname, "%s%s", WEB_ROOT, uri); 167 168 rc = asprintf(&fname, "%s%s", WEB_ROOT, uri); 206 169 if (rc < 0) 207 170 return ENOMEM; 208 209 intfd = open(fname, O_RDONLY);171 172 fd = open(fname, O_RDONLY); 210 173 if (fd < 0) { 211 rc = send_response(conn_sd, msg_not_found);174 printf("File '%s' not found.\n", fname); 212 175 free(fname); 213 return rc;214 } 215 176 return ENOENT; 177 } 178 216 179 free(fname); 217 218 rc = send_response(conn_sd, msg_ok);180 181 rc = send_response(conn_sd, ok_msg); 219 182 if (rc != EOK) 220 183 return rc; 221 184 222 185 while (true) { 223 ssize_tnr = read(fd, fbuf, BUFFER_SIZE);186 nr = read(fd, fbuf, BUFFER_SIZE); 224 187 if (nr == 0) 225 188 break; 226 189 227 190 if (nr < 0) { 228 191 close(fd); 229 192 return EIO; 230 193 } 231 194 232 195 rc = send(conn_sd, fbuf, nr, 0); 233 196 if (rc < 0) { 234 fprintf(stderr,"send() failed\n");197 printf("send() failed\n"); 235 198 close(fd); 236 199 return rc; 237 200 } 238 201 } 239 202 240 203 close(fd); 241 204 242 205 return EOK; 243 206 } … … 245 208 static int req_process(int conn_sd) 246 209 { 247 int rc = recv_line(conn_sd); 210 int rc; 211 char *uri, *end_uri; 212 213 rc = recv_line(conn_sd); 248 214 if (rc != EOK) { 249 fprintf(stderr,"recv_line() failed\n");215 printf("recv_line() failed\n"); 250 216 return rc; 251 217 } 252 253 fprintf(stderr, "Request:%s", lbuf);254 218 219 printf("%s", lbuf); 220 255 221 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, ' ');222 printf("Invalid HTTP method.\n"); 223 return EINVAL; 224 } 225 226 uri = lbuf + 4; 227 end_uri = str_chr(uri, ' '); 262 228 if (end_uri == NULL) { 263 229 end_uri = lbuf + lbuf_used - 2; 264 230 assert(*end_uri == '\r'); 265 231 } 266 232 267 233 *end_uri = '\0'; 268 fprintf(stderr, "Requested URI: %s\n", uri);269 234 printf("Requested URI '%s'.\n", uri); 235 270 236 if (!uri_is_valid(uri)) { 271 rc = send_response(conn_sd, msg_bad_request);272 return rc;273 } 274 237 printf("Invalid request URI.\n"); 238 return EINVAL; 239 } 240 275 241 return uri_get(uri, conn_sd); 276 242 } 277 243 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; 244 int main(int argc, char *argv[]) 245 { 246 struct sockaddr_in addr; 247 struct sockaddr_in raddr; 248 249 socklen_t raddr_len; 250 251 int listen_sd, conn_sd; 295 252 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 253 254 349 255 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); 256 addr.sin_port = htons(PORT_NUMBER); 257 258 rc = inet_pton(AF_INET, "127.0.0.1", (void *) &addr.sin_addr.s_addr); 354 259 if (rc != EOK) { 355 fprintf(stderr, "Error parsing network address (%s)\n", 356 str_error(rc)); 260 printf("Error parsing network address.\n"); 357 261 return 1; 358 262 } 359 360 fprintf(stderr, "Creating socket\n");361 362 intlisten_sd = socket(PF_INET, SOCK_STREAM, 0);263 264 printf("Creating socket.\n"); 265 266 listen_sd = socket(PF_INET, SOCK_STREAM, 0); 363 267 if (listen_sd < 0) { 364 fprintf(stderr, "Error creating listening socket (%s)\n", 365 str_error(listen_sd)); 366 return 2; 367 } 368 268 printf("Error creating listening socket.\n"); 269 return 1; 270 } 271 369 272 rc = bind(listen_sd, (struct sockaddr *) &addr, sizeof(addr)); 370 273 if (rc != EOK) { 371 fprintf(stderr, "Error binding socket (%s)\n", 372 str_error(rc)); 373 return 3; 374 } 375 274 printf("Error binding socket.\n"); 275 return 1; 276 } 277 376 278 rc = listen(listen_sd, BACKLOG_SIZE); 377 279 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); 280 printf("Error calling listen() (%d).\n", rc); 281 return 1; 282 } 283 284 printf("Listening for connections at port number %u.\n", PORT_NUMBER); 384 285 while (true) { 385 struct sockaddr_in raddr; 386 socklen_t raddr_len = sizeof(raddr); 387 int conn_sd = accept(listen_sd, (struct sockaddr *) &raddr, 286 raddr_len = sizeof(raddr); 287 conn_sd = accept(listen_sd, (struct sockaddr *) &raddr, 388 288 &raddr_len); 389 289 390 290 if (conn_sd < 0) { 391 fprintf(stderr, "accept() failed (%s)\n", str_error(rc));291 printf("accept() failed.\n"); 392 292 continue; 393 293 } 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 294 295 printf("Accepted connection, sd=%d.\n", conn_sd); 296 297 printf("Wait for client request\n"); 298 rbuf_out = rbuf_in = 0; 299 401 300 rc = req_process(conn_sd); 402 if (rc != EOK) 403 fprintf(stderr, "Error processing request (%s)\n", 404 str_error(rc)); 405 301 if (rc != EOK) 302 printf("Error processing request.\n"); 303 406 304 rc = closesocket(conn_sd); 407 305 if (rc != EOK) { 408 fprintf(stderr, "Error closing connection socket (%s)\n", 409 str_error(rc)); 306 printf("Error closing connection socket: %d\n", rc); 410 307 closesocket(listen_sd); 411 return 5;412 } 413 414 fprintf(stderr, "Connection closed\n");415 } 416 417 /* Not reached */308 return 1; 309 } 310 311 printf("Closed connection.\n"); 312 } 313 314 /* Not reached. */ 418 315 return 0; 419 316 }
Note:
See TracChangeset
for help on using the changeset viewer.