lws_intptr_t
[platform/upstream/libwebsockets.git] / lib / http2.c
index aa2189c..0bde700 100644 (file)
@@ -38,31 +38,33 @@ void lws_http2_init(struct http2_settings *settings)
        memcpy(settings, lws_http2_default_settings.setting, sizeof(*settings));
 }
 
-struct libwebsocket *
-lws_http2_wsi_from_id(struct libwebsocket *wsi, unsigned int sid)
+struct lws *
+lws_http2_wsi_from_id(struct lws *wsi, unsigned int sid)
 {
        do {
                if (wsi->u.http2.my_stream_id == sid)
                        return wsi;
-               
+
                wsi = wsi->u.http2.next_child_wsi;
        } while (wsi);
-       
+
        return NULL;
 }
 
-struct libwebsocket *
-lws_create_server_child_wsi(struct libwebsocket_context *context, struct libwebsocket *parent_wsi, unsigned int sid)
+struct lws *
+lws_create_server_child_wsi(struct lws_vhost *vhost, struct lws *parent_wsi,
+                           unsigned int sid)
 {
-       struct libwebsocket *wsi = libwebsocket_create_new_server_wsi(context);
-       
+       struct lws *wsi = lws_create_new_server_wsi(vhost);
+
        if (!wsi)
                return NULL;
-       
+
        /* no more children allowed by parent */
-       if (parent_wsi->u.http2.child_count + 1 == parent_wsi->u.http2.peer_settings.setting[LWS_HTTP2_SETTINGS__MAX_CONCURRENT_STREAMS])
-               return NULL;
-       
+       if (parent_wsi->u.http2.child_count + 1 ==
+           parent_wsi->u.http2.peer_settings.setting[
+                       LWS_HTTP2_SETTINGS__MAX_CONCURRENT_STREAMS])
+               goto bail;
        lws_http2_init(&wsi->u.http2.peer_settings);
        lws_http2_init(&wsi->u.http2.my_settings);
        wsi->u.http2.stream_id = sid;
@@ -72,49 +74,59 @@ lws_create_server_child_wsi(struct libwebsocket_context *context, struct libwebs
        wsi->u.http2.next_child_wsi = parent_wsi->u.http2.next_child_wsi;
        parent_wsi->u.http2.next_child_wsi = wsi;
        parent_wsi->u.http2.child_count++;
-       
+
        wsi->u.http2.my_priority = 16;
        wsi->u.http2.tx_credit = 65535;
-       
-       wsi->state = WSI_STATE_HTTP2_ESTABLISHED;
+
+       wsi->state = LWSS_HTTP2_ESTABLISHED;
        wsi->mode = parent_wsi->mode;
-       
-       wsi->protocol = &context->protocols[0];
-       libwebsocket_ensure_user_space(wsi);
 
-       lwsl_info("%s: %p new child %p, sid %d, user_space=%p\n", __func__, parent_wsi, wsi, sid, wsi->user_space);
-       
+       wsi->protocol = &vhost->protocols[0];
+       if (lws_ensure_user_space(wsi))
+               goto bail;
+
+       lwsl_info("%s: %p new child %p, sid %d, user_space=%p\n", __func__,
+                 parent_wsi, wsi, sid, wsi->user_space);
+
        return wsi;
+
+bail:
+       vhost->protocols[0].callback(wsi, LWS_CALLBACK_WSI_DESTROY,
+                              NULL, NULL, 0);
+       lws_free(wsi);
+
+       return NULL;
 }
 
-int lws_remove_server_child_wsi(struct libwebsocket_context *context, struct libwebsocket *wsi)
+int lws_remove_server_child_wsi(struct lws_context *context, struct lws *wsi)
 {
-       struct libwebsocket **w = &wsi->u.http2.parent_wsi;
+       struct lws **w = &wsi->u.http2.parent_wsi;
        do {
                if (*w == wsi) {
                        *w = wsi->u.http2.next_child_wsi;
                        (wsi->u.http2.parent_wsi)->u.http2.child_count--;
                        return 0;
                }
-               
+
                w = &((*w)->u.http2.next_child_wsi);
        } while (*w);
-       
+
        lwsl_err("%s: can't find %p\n", __func__, wsi);
        return 1;
 }
 
 int
-lws_http2_interpret_settings_payload(struct http2_settings *settings, unsigned char *buf, int len)
+lws_http2_interpret_settings_payload(struct http2_settings *settings,
+                                    unsigned char *buf, int len)
 {
        unsigned int a, b;
-       
+
        if (!len)
                return 0;
-       
+
        if (len < LWS_HTTP2_SETTINGS_LENGTH)
                return 1;
-       
+
        while (len >= LWS_HTTP2_SETTINGS_LENGTH) {
                a = (buf[0] << 8) | buf[1];
                if (a < LWS_HTTP2_SETTINGS__COUNT) {
@@ -125,24 +137,25 @@ lws_http2_interpret_settings_payload(struct http2_settings *settings, unsigned c
                len -= LWS_HTTP2_SETTINGS_LENGTH;
                buf += LWS_HTTP2_SETTINGS_LENGTH;
        }
-       
+
        if (len)
                return 1;
-       
+
        return 0;
 }
 
-struct libwebsocket *lws_http2_get_network_wsi(struct libwebsocket *wsi)
+struct lws *lws_http2_get_network_wsi(struct lws *wsi)
 {
        while (wsi->u.http2.parent_wsi)
                wsi = wsi->u.http2.parent_wsi;
-       
+
        return wsi;
 }
 
-int lws_http2_frame_write(struct libwebsocket *wsi, int type, int flags, unsigned int sid, unsigned int len, unsigned char *buf)
+int lws_http2_frame_write(struct lws *wsi, int type, int flags,
+                         unsigned int sid, unsigned int len, unsigned char *buf)
 {
-       struct libwebsocket *wsi_eff = lws_http2_get_network_wsi(wsi);
+       struct lws *wsi_eff = lws_http2_get_network_wsi(wsi);
        unsigned char *p = &buf[-LWS_HTTP2_FRAME_HEADER_LENGTH];
        int n;
 
@@ -155,24 +168,28 @@ int lws_http2_frame_write(struct libwebsocket *wsi, int type, int flags, unsigne
        *p++ = sid >> 16;
        *p++ = sid >> 8;
        *p++ = sid;
-       
-       lwsl_info("%s: %p (eff %p). type %d, flags 0x%x, sid=%d, len=%d\n",
-                 __func__, wsi, wsi_eff, type, flags, sid, len, wsi->u.http2.tx_credit);
-       
+
+       lwsl_info("%s: %p (eff %p). type %d, flags 0x%x, sid=%d, len=%d, tx_credit=%d\n",
+                 __func__, wsi, wsi_eff, type, flags, sid, len,
+                 wsi->u.http2.tx_credit);
+
        if (type == LWS_HTTP2_FRAME_TYPE_DATA) {
                if (wsi->u.http2.tx_credit < len)
-                       lwsl_err("%s: %p: sending payload len %d but tx_credit only %d!\n", len, wsi->u.http2.tx_credit);
+                       lwsl_err("%s: %p: sending payload len %d"
+                                " but tx_credit only %d!\n", __func__, wsi, len,
+                                wsi->u.http2.tx_credit);
                wsi->u.http2.tx_credit -= len;
        }
 
-       n = lws_issue_raw(wsi_eff, &buf[-LWS_HTTP2_FRAME_HEADER_LENGTH], len + LWS_HTTP2_FRAME_HEADER_LENGTH);
+       n = lws_issue_raw(wsi_eff, &buf[-LWS_HTTP2_FRAME_HEADER_LENGTH],
+                         len + LWS_HTTP2_FRAME_HEADER_LENGTH);
        if (n >= LWS_HTTP2_FRAME_HEADER_LENGTH)
                return n - LWS_HTTP2_FRAME_HEADER_LENGTH;
-       
+
        return n;
 }
 
-static void lws_http2_settings_write(struct libwebsocket *wsi, int n, unsigned char *buf)
+static void lws_http2_settings_write(struct lws *wsi, int n, unsigned char *buf)
 {
        *buf++ = n >> 8;
        *buf++ = n;
@@ -186,36 +203,35 @@ static const char * https_client_preface =
        "PRI * HTTP/2.0\x0d\x0a\x0d\x0aSM\x0d\x0a\x0d\x0a";
 
 int
-lws_http2_parser(struct libwebsocket_context *context,
-                    struct libwebsocket *wsi, unsigned char c)
+lws_http2_parser(struct lws *wsi, unsigned char c)
 {
-       struct libwebsocket *swsi;
+       struct lws *swsi;
        int n;
-       //dstruct libwebsocket *wsi_new;
 
        switch (wsi->state) {
-       case WSI_STATE_HTTP2_AWAIT_CLIENT_PREFACE:
+       case LWSS_HTTP2_AWAIT_CLIENT_PREFACE:
                if (https_client_preface[wsi->u.http2.count++] != c)
                        return 1;
 
                if (!https_client_preface[wsi->u.http2.count]) {
                        lwsl_info("http2: %p: established\n", wsi);
-                       wsi->state = WSI_STATE_HTTP2_ESTABLISHED_PRE_SETTINGS;
+                       wsi->state = LWSS_HTTP2_ESTABLISHED_PRE_SETTINGS;
                        wsi->u.http2.count = 0;
                        wsi->u.http2.tx_credit = 65535;
-                       
-                       /* 
+
+                       /*
                         * we must send a settings frame -- empty one is OK...
                         * that must be the first thing sent by server
                         * and the peer must send a SETTINGS with ACK flag...
                         */
-                       
-                       lws_set_protocol_write_pending(context, wsi, LWS_PPS_HTTP2_MY_SETTINGS);
+
+                       lws_set_protocol_write_pending(wsi,
+                                                      LWS_PPS_HTTP2_MY_SETTINGS);
                }
                break;
 
-       case WSI_STATE_HTTP2_ESTABLISHED_PRE_SETTINGS:
-       case WSI_STATE_HTTP2_ESTABLISHED:
+       case LWSS_HTTP2_ESTABLISHED_PRE_SETTINGS:
+       case LWSS_HTTP2_ESTABLISHED:
                if (wsi->u.http2.frame_state == LWS_HTTP2_FRAME_HEADER_LENGTH) { // payload
                        wsi->u.http2.count++;
                        wsi->u.http2.stream_wsi->u.http2.count = wsi->u.http2.count;
@@ -233,8 +249,15 @@ lws_http2_parser(struct libwebsocket_context *context,
                        case LWS_HTTP2_FRAME_TYPE_CONTINUATION:
                        case LWS_HTTP2_FRAME_TYPE_HEADERS:
                                lwsl_info(" %02X\n", c);
-                               if (lws_hpack_interpret(context, wsi->u.http2.stream_wsi, c))
+                               if (!wsi->u.http2.stream_wsi->u.hdr.ah)
+                                       if (lws_header_table_attach(wsi->u.http2.stream_wsi, 0)) {
+                                               lwsl_err("%s: Failed to get ah\n", __func__);
+                                               return 1;
+                                       }
+                               if (lws_hpack_interpret(wsi->u.http2.stream_wsi, c)) {
+                                       lwsl_notice("%s: lws_hpack_interpret failed\n", __func__);
                                        return 1;
+                               }
                                break;
                        case LWS_HTTP2_FRAME_TYPE_GOAWAY:
                                if (wsi->u.http2.count >= 5 && wsi->u.http2.count <= 8) {
@@ -269,7 +292,7 @@ lws_http2_parser(struct libwebsocket_context *context,
                        }
                        if (wsi->u.http2.count != wsi->u.http2.length)
                                break;
-                       
+
                        /* end of frame */
 
                        wsi->u.http2.frame_state = 0;
@@ -285,26 +308,26 @@ lws_http2_parser(struct libwebsocket_context *context,
                        case LWS_HTTP2_FRAME_TYPE_HEADERS:
                                /* service the http request itself */
                                lwsl_info("servicing initial http request, wsi=%p, stream wsi=%p\n", wsi, wsi->u.http2.stream_wsi);
-                               n = lws_http_action(context, swsi);
+                               n = lws_http_action(swsi);
                                (void)n;
                                lwsl_info("  action result %d\n", n);
                                break;
                        case LWS_HTTP2_FRAME_TYPE_PING:
                                if (wsi->u.http2.flags & LWS_HTTP2_FLAG_SETTINGS_ACK) { // ack
                                } else { /* they're sending us a ping request */
-                                       lws_set_protocol_write_pending(context, wsi, LWS_PPS_HTTP2_PONG);
+                                       lws_set_protocol_write_pending(wsi, LWS_PPS_HTTP2_PONG);
                                }
                                break;
                        case LWS_HTTP2_FRAME_TYPE_WINDOW_UPDATE:
                                wsi->u.http2.hpack_e_dep &= ~(1 << 31);
-                               if ((long long)swsi->u.http2.tx_credit + (unsigned long long)wsi->u.http2.hpack_e_dep > (~(1 << 31)))
+                               if ((lws_intptr_t)swsi->u.http2.tx_credit + (lws_intptr_t)wsi->u.http2.hpack_e_dep > (~(1 << 31)))
                                        return 1; /* actually need to close swsi not the whole show */
                                swsi->u.http2.tx_credit += wsi->u.http2.hpack_e_dep;
                                if (swsi->u.http2.waiting_tx_credit && swsi->u.http2.tx_credit > 0) {
                                        lwsl_info("%s: %p: waiting_tx_credit -> wait on writeable\n", __func__, wsi);
                                        swsi->u.http2.waiting_tx_credit = 0;
-                                       libwebsocket_callback_on_writable(context, swsi);
-                               }       
+                                       lws_callback_on_writable(swsi);
+                               }
                                break;
                        }
                        break;
@@ -336,21 +359,21 @@ lws_http2_parser(struct libwebsocket_context *context,
                        lwsl_info("frame: type 0x%x, flags 0x%x, sid 0x%x, len 0x%x\n",
                                  wsi->u.http2.type, wsi->u.http2.flags, wsi->u.http2.stream_id, wsi->u.http2.length);
                        wsi->u.http2.count = 0;
-                       
+
                        wsi->u.http2.stream_wsi = wsi;
                        if (wsi->u.http2.stream_id)
                                wsi->u.http2.stream_wsi = lws_http2_wsi_from_id(wsi, wsi->u.http2.stream_id);
-                       
+
                        switch (wsi->u.http2.type) {
                        case LWS_HTTP2_FRAME_TYPE_SETTINGS:
                                /* nonzero sid on settings is illegal */
                                if (wsi->u.http2.stream_id)
                                        return 1;
-                               
+
                                if (wsi->u.http2.flags & LWS_HTTP2_FLAG_SETTINGS_ACK) { // ack
                                } else
                                        /* non-ACK coming in means we must ACK it */
-                                       lws_set_protocol_write_pending(context, wsi, LWS_PPS_HTTP2_ACK_SETTINGS);
+                                       lws_set_protocol_write_pending(wsi, LWS_PPS_HTTP2_ACK_SETTINGS);
                                break;
                        case LWS_HTTP2_FRAME_TYPE_PING:
                                if (wsi->u.http2.stream_id)
@@ -367,23 +390,26 @@ lws_http2_parser(struct libwebsocket_context *context,
                                lwsl_info("LWS_HTTP2_FRAME_TYPE_HEADERS: stream_id = %d\n", wsi->u.http2.stream_id);
                                if (!wsi->u.http2.stream_id)
                                        return 1;
-                               if (!wsi->u.http2.stream_wsi)
-                                       wsi->u.http2.stream_wsi = lws_create_server_child_wsi(context, wsi, wsi->u.http2.stream_id);
-                                                               
+                               if (!wsi->u.http2.stream_wsi) {
+                                       wsi->u.http2.stream_wsi =
+                                               lws_create_server_child_wsi(wsi->vhost, wsi, wsi->u.http2.stream_id);
+                                       wsi->u.http2.stream_wsi->http2_substream = 1;
+                               }
+
                                /* END_STREAM means after servicing this, close the stream */
                                wsi->u.http2.END_STREAM = !!(wsi->u.http2.flags & LWS_HTTP2_FLAG_END_STREAM);
                                lwsl_info("%s: headers END_STREAM = %d\n",__func__, wsi->u.http2.END_STREAM);
 update_end_headers:
                                /* no END_HEADERS means CONTINUATION must come */
                                wsi->u.http2.END_HEADERS = !!(wsi->u.http2.flags & LWS_HTTP2_FLAG_END_HEADERS);
-                               
+
                                swsi = wsi->u.http2.stream_wsi;
                                if (!swsi)
                                        return 1;
 
-                               
+
                                /* prepare the hpack parser at the right start */
-                               
+
                                swsi->u.http2.flags = wsi->u.http2.flags;
                                swsi->u.http2.length = wsi->u.http2.length;
                                swsi->u.http2.END_STREAM = wsi->u.http2.END_STREAM;
@@ -409,29 +435,29 @@ update_end_headers:
                }
                break;
        }
-       
+
        return 0;
 }
 
-int lws_http2_do_pps_send(struct libwebsocket_context *context, struct libwebsocket *wsi)
+int lws_http2_do_pps_send(struct lws_context *context, struct lws *wsi)
 {
-       unsigned char settings[LWS_SEND_BUFFER_PRE_PADDING + 6 * LWS_HTTP2_SETTINGS__COUNT];
-       struct libwebsocket *swsi;
+       unsigned char settings[LWS_PRE + 6 * LWS_HTTP2_SETTINGS__COUNT];
+       struct lws *swsi;
        int n, m = 0;
 
        lwsl_debug("%s: %p: %d\n", __func__, wsi, wsi->pps);
-       
+
        switch (wsi->pps) {
        case LWS_PPS_HTTP2_MY_SETTINGS:
                for (n = 1; n < LWS_HTTP2_SETTINGS__COUNT; n++)
                        if (wsi->u.http2.my_settings.setting[n] != lws_http2_default_settings.setting[n]) {
                                lws_http2_settings_write(wsi, n,
-                                                        &settings[LWS_SEND_BUFFER_PRE_PADDING + m]);
+                                                        &settings[LWS_PRE + m]);
                                m += sizeof(wsi->u.http2.one_setting);
                        }
                n = lws_http2_frame_write(wsi, LWS_HTTP2_FRAME_TYPE_SETTINGS,
                                          0, LWS_HTTP2_STREAM_ID_MASTER, m,
-                                         &settings[LWS_SEND_BUFFER_PRE_PADDING]);
+                                         &settings[LWS_PRE]);
                if (n != m) {
                        lwsl_info("send %d %d\n", n, m);
                        return 1;
@@ -441,34 +467,35 @@ int lws_http2_do_pps_send(struct libwebsocket_context *context, struct libwebsoc
                /* send ack ... always empty */
                n = lws_http2_frame_write(wsi, LWS_HTTP2_FRAME_TYPE_SETTINGS,
                        1, LWS_HTTP2_STREAM_ID_MASTER, 0,
-                       &settings[LWS_SEND_BUFFER_PRE_PADDING]);
+                       &settings[LWS_PRE]);
                if (n) {
                        lwsl_err("ack tells %d\n", n);
                        return 1;
                }
                /* this is the end of the preface dance then? */
-               if (wsi->state == WSI_STATE_HTTP2_ESTABLISHED_PRE_SETTINGS) {
-                       wsi->state = WSI_STATE_HTTP2_ESTABLISHED;
-                       
-                       wsi->u.http.fd = LWS_INVALID_FILE;
-                       
+               if (wsi->state == LWSS_HTTP2_ESTABLISHED_PRE_SETTINGS) {
+                       wsi->state = LWSS_HTTP2_ESTABLISHED;
+
+                       wsi->u.http.fop_fd = NULL;
+
                        if (lws_is_ssl(lws_http2_get_network_wsi(wsi))) {
-                               lwsl_info("skipping nonexistant ssl upgrade headers\n");
+                               lwsl_info("skipping nonexistent ssl upgrade headers\n");
                                break;
                        }
-                       
-                       /* 
+
+                       /*
                         * we need to treat the headers from this upgrade
                         * as the first job.  These need to get
                         * shifted to stream ID 1
                         */
                        lwsl_info("%s: setting up sid 1\n", __func__);
-                       
-                       swsi = wsi->u.http2.stream_wsi = lws_create_server_child_wsi(context, wsi, 1);
+
+                       swsi = wsi->u.http2.stream_wsi =
+                                       lws_create_server_child_wsi(wsi->vhost, wsi, 1);
                        /* pass on the initial headers to SID 1 */
                        swsi->u.http.ah = wsi->u.http.ah;
                        wsi->u.http.ah = NULL;
-                       
+
                        lwsl_info("%s: inherited headers %p\n", __func__, swsi->u.http.ah);
                        swsi->u.http2.tx_credit = wsi->u.http2.peer_settings.setting[LWS_HTTP2_SETTINGS__INITIAL_WINDOW_SIZE];
                        lwsl_info("initial tx credit on conn %p: %d\n", swsi, swsi->u.http2.tx_credit);
@@ -476,15 +503,15 @@ int lws_http2_do_pps_send(struct libwebsocket_context *context, struct libwebsoc
                        /* demanded by HTTP2 */
                        swsi->u.http2.END_STREAM = 1;
                        lwsl_info("servicing initial http request\n");
-                       return lws_http_action(context, swsi);
+                       return lws_http_action(swsi);
                }
                break;
        case LWS_PPS_HTTP2_PONG:
-               memcpy(&settings[LWS_SEND_BUFFER_PRE_PADDING], wsi->u.http2.ping_payload, 8);
+               memcpy(&settings[LWS_PRE], wsi->u.http2.ping_payload, 8);
                n = lws_http2_frame_write(wsi, LWS_HTTP2_FRAME_TYPE_PING,
                                          LWS_HTTP2_FLAG_SETTINGS_ACK,
                                          LWS_HTTP2_STREAM_ID_MASTER, 8,
-                                         &settings[LWS_SEND_BUFFER_PRE_PADDING]);
+                                         &settings[LWS_PRE]);
                if (n != 8) {
                        lwsl_info("send %d %d\n", n, m);
                        return 1;
@@ -493,11 +520,11 @@ int lws_http2_do_pps_send(struct libwebsocket_context *context, struct libwebsoc
        default:
                break;
        }
-       
+
        return 0;
 }
 
-struct libwebsocket * lws_http2_get_nth_child(struct libwebsocket *wsi, int n)
+struct lws * lws_http2_get_nth_child(struct lws *wsi, int n)
 {
        do {
                wsi = wsi->u.http2.next_child_wsi;