1/** 2 * \file 3 * \brief HTTP server 4 * 5 * \bug All calls to tcp_write currently use TCP_WRITE_FLAG_COPY, causing 6 * the data to be copied to LWIP's internal memory pool. This is necessary, 7 * because we lack the VM support necessary to do a reverse mapping for 8 * arbitrary memory regions. 9 */ 10 11/* 12 * Copyright (c) 2008, 2009, ETH Zurich. 13 * All rights reserved. 14 * 15 * This file is distributed under the terms in the attached LICENSE file. 16 * If you do not find this file, copies can be found by writing to: 17 * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group. 18 */ 19 20#include <stdio.h> 21#include <sys/param.h> 22#include <barrelfish/barrelfish.h> 23#include <netinet/in.h> 24#include <net_sockets/net_sockets.h> 25#include <netbench/netbench.h> 26#include <debug_log/debug_log.h> 27 28#define LWIP_IPV4 29#include <lwip/ip_addr.h> 30 31#include "http_cache.h" 32#include "webserver_network.h" 33#include "webserver_debug.h" 34#include "webserver_session.h" 35 36#define HTTP_PORT 80 37 38#define CRLF "\r\n" 39#define HTTP_HEADER_COMMON "Server: Barrelfish" CRLF 40#define HTTP_HEADER_200 "HTTP/1.0 200 OK" CRLF HTTP_HEADER_COMMON 41#define HTTP_HEADER_404 "HTTP/1.0 404 Not Found" CRLF HTTP_HEADER_COMMON 42#define HTTP_HEADER_500 "HTTP/1.0 500 Internal Server Error" CRLF HTTP_HEADER_COMMON 43 44#define HTTP_MIME_HTML "Content-type: text/html; charset=utf-8" CRLF 45#define HTTP_MIME_GIF "Content-type: image/gif" CRLF 46#define HTTP_MIME_JPG "Content-type: image/jpeg" CRLF 47#define HTTP_MIME_PDF "Content-type: application/pdf" CRLF 48#define HTTP_MIME_TAR "Content-type: application/x-tar" CRLF 49#define HTTP_MIME_GZIP "Content-type: application/x-gzip" CRLF 50#define HTTP_MIME_BZIP2 "Content-type: application/x-bzip2" CRLF 51#define HTTP_MIME_OCTET "Content-type: application/octet-stream" CRLF 52 53 54static const char notfound_reply[] = 55 HTTP_HEADER_404 HTTP_MIME_HTML CRLF 56 "<html>" CRLF 57 "<body>" CRLF 58 "<h1>404 Not Found</h1>" CRLF 59 "<p>The requested URL was not found.</p>" CRLF 60 "</body>" CRLF 61 "</html>" CRLF; 62 63static const char error_reply[] = 64 HTTP_HEADER_500 HTTP_MIME_HTML CRLF 65 "<html>" CRLF 66 "<body>" CRLF 67 "<h1>500 Internal Server Error</h1>" CRLF 68 "<p>Bad stuff happened. Damn.</p>" CRLF 69 "</body>" CRLF 70 "</html>" CRLF; 71 72static const char header_html[] = HTTP_HEADER_200 HTTP_MIME_HTML CRLF; 73static const char header_gif[] = HTTP_HEADER_200 HTTP_MIME_GIF CRLF; 74static const char header_jpg[] = HTTP_HEADER_200 HTTP_MIME_JPG CRLF; 75static const char header_pdf[] = HTTP_HEADER_200 HTTP_MIME_PDF CRLF; 76static const char header_bz2[] = HTTP_HEADER_200 HTTP_MIME_BZIP2 CRLF; 77static const char header_gz[] = HTTP_HEADER_200 HTTP_MIME_GZIP CRLF; 78static const char header_octet[] = HTTP_HEADER_200 HTTP_MIME_OCTET CRLF; 79 80#if 0 81 82#define MAX_DURATIONS 1000 83 84#define INST_BEGIN \ 85 static uint64_t _dursum = 0, _dur = 0; \ 86 uint64_t _begin = rdtsc(); 87 88#define INST_END \ 89 _dursum += rdtsc() - _begin; \ 90 _dur++; \ 91 if(_dur == MAX_DURATIONS) { \ 92 DEBUGPRINT("%s: %lu\n", __func__, _dursum / MAX_DURATIONS); \ 93 _dur = 0; _dursum = 0; \ 94 } 95 96#else 97 98#define INST_BEGIN 99#define INST_END 100 101#endif 102 103/* GLOBAL STATE */ 104static int parallel_connections = 0; /* number of connections alive at moment */ 105static int request_counter = 0; /* Total no. of requests received till now */ 106/* above both are for debugging purpose only */ 107 108 109 110static struct http_conn *http_conn_new(void) 111{ 112 struct http_conn *newconn = malloc(sizeof(struct http_conn)); 113 assert (newconn != NULL); 114 memset (newconn, 0, sizeof(struct http_conn)); 115 116 newconn->state = HTTP_STATE_NEW; 117 newconn->request_no = request_counter++; 118 119 DEBUGPRINT ("%d: http_conn created [p %d] %lu %lu\n", newconn->request_no, 120 parallel_connections, newconn->header_pos, newconn->header_length); 121 ++parallel_connections; 122 return newconn; 123} 124 125 126static void http_conn_free(struct http_conn *conn) 127{ 128 DEBUGPRINT ("%d: http_conn_free freeing [p %d]\n", conn->request_no, 129 parallel_connections); 130 131 if(conn->request != NULL) { 132 free(conn->request); 133 } 134 /* decrementing the reference to buff_holder */ 135 decrement_buff_holder_ref (conn->hbuff); 136 free(conn); 137 --parallel_connections; 138} 139 140/* increments the reference counter and returns the incremented value */ 141long increment_http_conn_reference (struct http_conn *cs) 142{ 143 ++cs->ref_count; 144 return (cs->ref_count); 145} /* end function: increment_http_conn_reference */ 146 147/* This function decrements the references to http_conn 148 * and if references reach 0, the memory of struct is released. */ 149long decrement_http_conn_reference (struct http_conn *cs) 150{ 151 --cs->ref_count; 152 if (cs->mark_invalid) { 153 /* connection is no longer valid */ 154 if (cs->ref_count <= 0) { 155 /* no one is using the connection */ 156 /* so, free up the the memory */ 157 http_conn_free(cs); 158 return 0; 159 } 160 } /* end if : invalid http_conn */ 161 return cs->ref_count; 162} /* end function: decrement_reference */ 163 164 165static void http_conn_invalidate (struct http_conn *conn) 166{ 167 DEBUGPRINT ("%d: http_conn_invalidate\n", conn->request_no); 168 conn->mark_invalid = 1; 169 decrement_http_conn_reference (conn); 170} 171 172 173// static void http_server_err(void *arg, errval_t err) 174// { 175// struct http_conn *conn = arg; 176// 177// DEBUGPRINT("http_server_err! %p %d\n", arg, err); 178// if(conn != NULL) { 179// DEBUGPRINT("%d: http_server_err! %p %d\n", conn->request_no, arg, err); 180// http_conn_invalidate (conn); 181// } else { 182// DEBUGPRINT("http_server_err! %p %d\n", arg, err); 183// } 184// } 185// 186// 187static void http_server_close(struct net_socket *socket, struct http_conn *cs) 188{ 189/* 190 printf("%s %s %s %hu.%hu.%hu.%hu in %"PU"\n", 191 cs->hbuff->data ? "200" : "404", cs->request, cs->filename, 192 ip4_addr1(&cs->pcb->remote_ip), ip4_addr2(&cs->pcb->remote_ip), 193 ip4_addr3(&cs->pcb->remote_ip), ip4_addr4(&cs->pcb->remote_ip), 194 in_seconds(get_time_delta(&cs->start_ts))); 195*/ 196 // debug_printf_to_log("%s(%d): %p", __func__, socket->descriptor, __builtin_return_address(0)); 197 DEBUGPRINT("%d: http_server_close freeing the connection\n", 198 cs->request_no); 199 200 assert(cs); 201 // debug_printf("%s(%d):\n", __func__, socket->descriptor); 202 net_close(socket); 203} 204 205static void http_server_closed(void *arg, struct net_socket *socket) 206{ 207 // debug_printf("%s(%d):\n", __func__, socket->descriptor); 208 struct http_conn *cs = arg; 209 http_conn_invalidate(cs); 210} 211 212static errval_t trysend(struct net_socket *socket, const void *data, size_t *len, bool 213more) 214{ 215 size_t sendlen; 216 errval_t err; 217 218 for (sendlen = 0; sendlen < *len;) { 219 void *buffer; 220 size_t s = *len - sendlen; 221 s = s > 16000 ? 16000: s; 222 223 buffer = net_alloc(s); 224 if (!buffer) 225 break; 226 memcpy(buffer, data + sendlen, s); 227 err = net_send(socket, buffer, s); 228 assert(err_is_ok(err)); 229 sendlen += s; 230 } 231 *len = sendlen; 232 return SYS_ERR_OK; 233} 234 235static void http_send_data(struct net_socket *socket, struct http_conn *conn) 236{ 237 errval_t err; 238 const void *data; 239 size_t len; 240 241// debug_printf_to_log("%s(%d): %p %d", __func__, socket->descriptor, conn, conn->state); 242 switch (conn->state) { 243 case HTTP_STATE_SENDHEADER: 244 DEBUGPRINT ("%d: http_send_data: header_pos %lu < header_len %lu\n", 245 conn->request_no, conn->header_pos, conn->header_length); 246 assert(conn->header_pos < conn->header_length); 247 data = &conn->header[conn->header_pos]; 248 len = conn->header_length - conn->header_pos; 249 // debug_printf_to_log("%s(%d): header %zd:%zd", __func__, socket->descriptor, conn->header_pos, len); 250 err = trysend(socket, data, &len, (conn->hbuff->data != NULL)); 251 if (err != SYS_ERR_OK) { 252 DEBUGPRINT("http_send_data(): Error %zd sending header\n", err); 253 return; // will retry 254 } 255 256 conn->header_pos += len; 257 DEBUGPRINT ("%d: http_send_data incr: hdr_pos %lu < hdr_len %lu\n", 258 conn->request_no, conn->header_pos, conn->header_length); 259 if (conn->header_pos == conn->header_length) { 260 conn->state = HTTP_STATE_SENDFILE; // fall through below 261 conn->reply_pos = 0; 262 conn->reply_sent = 0; 263 } else { 264 break; 265 } 266 267 case HTTP_STATE_SENDFILE: 268 if (conn->hbuff->data == NULL) { 269 conn->state = HTTP_STATE_CLOSING; 270 break; 271 } 272 data = conn->hbuff->data + conn->reply_pos; /* pointer arithmatic */ 273 len = conn->hbuff->len - conn->reply_pos; 274 size_t maxlen = 16000 - (conn->reply_pos - conn->reply_sent); 275 // debug_printf("%s: %zd %zd\n", __func__, len, maxlen); 276 if (len > maxlen) 277 len = maxlen; 278 // debug_printf_to_log("%s(%d): file %zd:%zd", __func__, socket->descriptor, conn->reply_pos, len); 279 err = trysend(socket, data, &len, false); 280 if (err != SYS_ERR_OK) { 281 DEBUGPRINT("http_send_data(): Error %zd sending payload\n", err); 282 return; // will retry 283 } 284 conn->reply_pos += len; 285// debug_printf_to_log("%s(%d): %zd %zd\n", __func__, socket->descriptor, conn->reply_pos, conn->hbuff->len); 286 if (conn->reply_pos == conn->hbuff->len) { 287 conn->state = HTTP_STATE_CLOSING; 288 http_server_close(socket, conn); 289 } 290 break; 291 292 default: 293 DEBUGPRINT ("http_send_data(): Wrong state! (%d)\n", conn->state); 294 break; 295 } 296} 297 298/* This function is called periodically from TCP. 299 * and is also responsible for taking care of stale connections. 300**/ 301// static errval_t http_poll(void *arg, struct net_socket *socket) 302// { 303// struct http_conn *conn = arg; 304// 305// if (conn == NULL && socket->state == ESTABLISHED) { 306// tcp_abort(socket); 307// return ERR_ABRT; 308// } else if (conn != NULL && (conn->state == HTTP_STATE_SENDHEADER 309// || conn->state == HTTP_STATE_SENDFILE)) { 310// if (++conn->retries == 4) { 311// DEBUGPRINT ("connection closed, tried too hard\n"); 312// http_conn_invalidate (conn); 313// net_delete_socket(socket); 314// return ERR_ABRT; 315// } 316// http_send_data(socket, conn); 317// if (conn->state == HTTP_STATE_CLOSING) { 318// DEBUGPRINT ("%d: http_poll closing the connection\n", 319// conn->request_no); 320// http_server_close(socket, conn); 321// } else { 322// // tcp_output(socket); 323// } 324// } else if (conn != NULL && (conn->state == HTTP_STATE_NEW 325// || conn->state == HTTP_STATE_REQUEST)) { 326// /* abort connections that sit open for too long without sending a 327// request */ 328// if (++conn->retries == 60) { 329// DEBUGPRINT("connection in state %d too long, aborted\n", 330// conn->state); 331// DEBUGPRINT("connection in state %d too long, aborted\n", 332// conn->state); 333// 334// http_conn_invalidate (conn); 335// net_delete_socket(socket); 336// return ERR_ABRT; 337// } 338// } 339// return SYS_ERR_OK; 340// } /* end function: http_poll */ 341 342/* called when data is successfully sent */ 343static void http_server_sent(void *arg, struct net_socket *socket, void *buffer, size_t size) 344{ 345 struct http_conn *conn = arg; 346 347 // debug_printf("%s(%d): %d\n", __func__, socket->descriptor, conn->state == HTTP_STATE_CLOSING); 348 // debug_printf_to_log("%s(%d):", __func__, socket->descriptor); 349 assert(conn); 350 net_free(buffer); 351 352 // debug_printf("%s: %zd %zd:%zd %zd:%zd\n", __func__, size, conn->header_pos, conn->header_sent, conn->reply_pos, conn->reply_sent); 353 if (conn->header_sent < conn->header_pos) 354 conn->header_sent += size; 355 else 356 conn->reply_sent += size; 357 358 switch(conn->state) { 359 case HTTP_STATE_SENDHEADER: 360 case HTTP_STATE_SENDFILE: 361 // Need to send more data? 362 http_send_data(socket, conn); 363 break; 364 case HTTP_STATE_CLOSING: 365 DEBUGPRINT("%d: http_server_sent closing the connection\n", 366 conn->request_no); 367// debug_printf_to_log("%s(%d): %ld:%ld %ld:%ld", __func__, socket->descriptor, conn->header_pos, conn->header_sent, conn->reply_pos, conn->reply_sent); 368 // if (conn->header_pos == conn->header_sent && conn->reply_pos == conn->reply_sent) { 369// debug_printf("%s.%d: %zd\n", __func__, __LINE__, size); 370 // http_server_close(socket, conn); 371 // } 372 break; 373 374 default: 375 break; 376 } 377} 378 379static const void *make_header(const char *uri, size_t *retlen) 380{ 381 /* FIXME: hack to guess MIME type */ 382 size_t urilen = strlen(uri); 383 if (strcmp(uri + urilen - 5, ".html") == 0) { 384 *retlen = sizeof(header_html) - 1; // -1 for '\0' 385 return header_html; 386 } else if (strcmp(uri + urilen - 4, ".gif") == 0) { 387 *retlen = sizeof(header_gif) - 1; 388 return header_gif; 389 } else if (strcmp(uri + urilen - 4, ".jpg") == 0) { 390 *retlen = sizeof(header_jpg) - 1; 391 return header_jpg; 392 } else if (strcmp(uri + urilen - 4, ".pdf") == 0) { 393 *retlen = sizeof(header_pdf) - 1; 394 return header_pdf; 395 } else if (strcmp(uri + urilen - 4, ".bz2") == 0) { 396 *retlen = sizeof(header_bz2) - 1; 397 return header_bz2; 398 } else if (strcmp(uri + urilen - 3, ".gz") == 0) { 399 *retlen = sizeof(header_gz) - 1; 400 return header_gz; 401 } else { 402 *retlen = sizeof(header_octet) - 1; 403 return header_octet; 404 } 405} 406 407/* Get one byte from the 4-byte address */ 408#define ip_addr1(ipaddr) (((const u8_t*)(&(ipaddr)->s_addr))[0]) 409#define ip_addr2(ipaddr) (((const u8_t*)(&(ipaddr)->s_addr))[1]) 410#define ip_addr3(ipaddr) (((const u8_t*)(&(ipaddr)->s_addr))[2]) 411#define ip_addr4(ipaddr) (((const u8_t*)(&(ipaddr)->s_addr))[3]) 412 413/* callback function to fetch file 414 This function is responsible for sending the fetched file */ 415static void send_response(struct http_conn *cs) 416{ 417 418 if (cs->error) { 419 DEBUGPRINT ("%d: BIGERROR Sending the response back of size %lu\n", 420 cs->request_no, cs->reply_pos); 421 DEBUGPRINT("%s %s %s %hu.%hu.%hu.%hu\n", "500", 422 cs->request, cs->filename, 423 ip_addr1(&cs->pcb->connected_address), ip_addr2(&cs->pcb->connected_address), 424 ip_addr3(&cs->pcb->connected_address), ip_addr4(&cs->pcb->connected_address)); 425 426 cs->header = error_reply; 427 cs->header_length = sizeof(error_reply) - 1; 428 cs->header_sent = 0; 429 } else { 430 DEBUGPRINT ("%d: Sending the response back of size %lu\n", 431 cs->request_no, cs->reply_pos); 432 DEBUGPRINT("%s %s %s %hu.%hu.%hu.%hu\n", cs->hbuff->data ? 433 "200" : "404", cs->request, cs->filename, 434 ip_addr1(&cs->pcb->connected_address), ip_addr2(&cs->pcb->connected_address), 435 ip_addr3(&cs->pcb->connected_address), ip_addr4(&cs->pcb->connected_address)); 436 437 if (cs->hbuff->data == NULL) { 438 /* not found, send 404 */ 439 DEBUGPRINT ("%d: making 404 case\n",cs->request_no); 440 DEBUGPRINT ("witness: header_pos %lu < header_len %lu\n", 441 cs->header_pos, cs->header_length); 442 443 cs->header = notfound_reply; 444 cs->header_length = sizeof(notfound_reply) - 1; 445 cs->header_sent = 0; 446 } else { 447 /* found, send static header */ 448 cs->header = make_header(cs->filename, &cs->header_length); 449 cs->header_sent = 0; 450 } 451 } /* end else: internal error */ 452 453 /* send data */ 454 cs->state = HTTP_STATE_SENDHEADER; 455 cs->retries = 0; 456 http_send_data(cs->pcb, cs); 457 458 /* did we send the whole page? */ 459 // if (cs->state == HTTP_STATE_CLOSING) { 460 // DEBUGPRINT("%d: send_response closing the connection\n", 461 // cs->request_no); 462// debug_printf("%s.%d:\n", __func__, __LINE__); 463 // http_server_close(cs->pcb, cs); 464 // } else { 465 // tcp_output(cs->pcb); 466 // } 467} /* end function: send_response */ 468 469// static errval_t http_server_recv(void *arg, struct net_socket *socket, struct pbuf *p, 470// errval_t err); 471// 472static void http_server_recv(void *arg, struct net_socket *socket, void *data, size_t size, struct in_addr ip_address, uint16_t port) 473{ 474 struct http_conn *conn = arg; 475 476 DEBUGPRINT("%d, http_server_recv called\n", conn->request_no); 477 // debug_printf_to_log("%s(%d): %ld %d\n", __func__, socket->descriptor, size, conn->state); 478 479 // check if connection closed 480 assert(conn); 481 if (size == 0) { 482 DEBUGPRINT("%d, closing from http_server_recv\n", conn->request_no); 483// debug_printf("%s.%d:\n", __func__, __LINE__); 484 conn->state = HTTP_STATE_CLOSING; 485 http_server_close(socket, conn); 486 return; 487 } 488 489 switch(conn->state) { 490 case HTTP_STATE_NEW: 491 conn->state = HTTP_STATE_REQUEST; 492 // Fall through... 493 494 case HTTP_STATE_REQUEST: 495 /* don't send an immediate ack here, do it later with the data */ 496 // socket->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW); 497 498 /* accumulate the request data */ 499 conn->request_length += size; 500 conn->request = realloc(conn->request, conn->request_length + 1); 501 char *d = conn->request + conn->request_length - size; 502 memcpy(d, data, size); 503 d += size; 504 *d = '\0'; 505 506 // pbuf_free(p); 507 508 // have we seen the end of the request yet? 509 if (strstr(conn->request, CRLF CRLF) == NULL) { 510 break; 511 } 512 513 // ignore everything after the first line 514 char *cp = strstr(conn->request, CRLF); 515 assert(cp != NULL); 516 *cp = '\0'; 517 518 // Parse request: break into method and URI 519 cp = strchr(conn->request, ' '); 520 if (cp == NULL) { 521 goto invalid; 522 } 523 *cp = '\0'; 524 const char *uri = cp + 1; 525 cp = strrchr(uri, ' '); 526 if (cp == NULL) { 527 goto invalid; 528 } 529 *cp = '\0'; 530 531 if (strcmp(conn->request, "GET") != 0) { 532 goto invalid; 533 } 534 535 // drop a leading / 536 if (uri[0] == '/') { 537 uri++; 538 } 539 540 // if URI is now empty, look for index.html 541 if (uri[0] == '\0') { 542 uri = "index.html"; 543 } 544 545 conn->filename = (char *)uri; 546 conn->callback = send_response; 547 conn->pcb = socket; 548 conn->start_ts = rdtsc(); 549 /* for callback execution */ 550 errval_t e = http_cache_lookup(uri, conn); 551 if (e != SYS_ERR_OK) { 552 conn->error = 1; 553 send_response(conn); 554 } 555 break; 556 557 default: 558 DEBUGPRINT("http_server_recv(): data received in wrong state (%d)!\n", 559 conn->state); 560 conn->error = 1; 561 send_response(conn); 562 break; 563 } 564 return; 565 566invalid: 567 DEBUGPRINT("invalid request: %s\n", conn->request); 568 DEBUGPRINT("%d: invalid request: %s\n",conn->request_no, conn->request); 569 conn->state = HTTP_STATE_CLOSING; 570 http_server_close(socket, conn); 571 return; 572} 573 574static void http_server_accept(void *arg, struct net_socket *socket) 575{ 576// #if TCP_LISTEN_BACKLOG 577// /* Decrease the listen backlog counter */ 578// struct tcp_pcb_listen *lpcb = (struct tcp_pcb_listen*)arg; 579// #endif 580 // debug_printf_to_log("%s(%d):", __func__, socket->descriptor); 581 struct http_conn *conn = http_conn_new(); 582 DEBUGPRINT("accpet called: %s\n", conn->request); 583 increment_http_conn_reference (conn); 584 /* NOTE: This initial increment marks the basic assess and it will be 585 decremented by http_server_invalidate */ 586 587 net_set_user_state(socket, conn); 588 net_set_on_received(socket, http_server_recv); 589 net_set_on_sent(socket, http_server_sent); 590 net_set_on_closed(socket, http_server_closed); 591 592 // tcp_err(socket, http_server_err); 593 // tcp_poll(socket, http_poll, 4); 594} 595 596 597static void realinit(void) 598{ 599 uint64_t ts = rdtsc(); 600 struct net_socket *pcb = net_tcp_socket(); 601// err_t e = tcp_bind(pcb, IP_ADDR_ANY, (HTTP_PORT + disp_get_core_id())); 602 errval_t e = net_bind(pcb, (struct in_addr){(INADDR_ANY)}, HTTP_PORT); 603 assert(e == SYS_ERR_OK); 604 605 e = net_listen(pcb, 100); 606 assert(e == SYS_ERR_OK); 607 608 net_set_on_accepted(pcb, http_server_accept); 609 printf("HTTP setup time %"PU"\n", in_seconds(get_time_delta(&ts))); 610 printf("#######################################################\n"); 611 printf("Starting webserver\n"); 612 printf("#######################################################\n"); 613 614} 615 616void http_server_init(struct in_addr server, const char *path) 617{ 618 http_cache_init(server, path, realinit); 619} 620 621 622uint64_t get_time_delta(uint64_t *l_ts) 623{ 624 uint64_t ct = rdtsc(); 625 uint64_t delta = ct - *l_ts; 626 *l_ts = ct; 627 return delta; 628 // return delta / (2800 * 1000); 629} // end function: get_time_delta 630