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