1
0
Fork 0
mirror of https://github.com/warmcat/libwebsockets.git synced 2025-03-09 00:00:04 +01:00

http2 handle flags

Signed-off-by: Andy Green <andy.green@linaro.org>
This commit is contained in:
Andy Green 2014-10-17 08:38:44 +08:00
parent 0c51239023
commit 91b0589795
6 changed files with 85 additions and 23 deletions

View file

@ -212,6 +212,7 @@ lws_http2_parser(struct libwebsocket_context *context,
return 1;
break;
case LWS_HTTP2_FRAME_TYPE_HEADERS:
lwsl_info(" %02X\n", c);
if (lws_hpack_interpret(context, wsi->u.http2.stream_wsi, c))
return 1;
break;
@ -276,11 +277,16 @@ lws_http2_parser(struct libwebsocket_context *context,
if (wsi->u.http2.stream_id)
return 1;
if (wsi->u.http2.flags & 1) { // ack
} else {
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);
}
break;
case LWS_HTTP2_FRAME_TYPE_CONTINUATION:
if (wsi->u.http2.END_HEADERS)
return 1;
goto update_end_headers;
case LWS_HTTP2_FRAME_TYPE_HEADERS:
lwsl_info("LWS_HTTP2_FRAME_TYPE_HEADERS: stream_id = %d\n", wsi->u.http2.stream_id);
if (!wsi->u.http2.stream_id)
@ -291,6 +297,13 @@ lws_http2_parser(struct libwebsocket_context *context,
if (!wsi->u.http2.stream_wsi)
return 1;
/* END_STREAM means after servicing this, close the stream */
wsi->u.http2.END_STREAM = !!(wsi->u.http2.flags & LWS_HTTP2_FLAG_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);
break;
}
if (wsi->u.http2.length == 0)
wsi->u.http2.frame_state = 0;

View file

@ -1089,6 +1089,8 @@ lws_add_http_header_status(struct libwebsocket_context *context,
unsigned char **p,
unsigned char *end);
LWS_EXTERN int lws_http_transaction_completed(struct libwebsocket *wsi);
#ifdef LWS_USE_LIBEV
LWS_VISIBLE LWS_EXTERN int
libwebsocket_initloop(

View file

@ -441,7 +441,7 @@ send_raw:
n = LWS_HTTP2_FRAME_TYPE_DATA;
if (protocol == LWS_WRITE_HTTP_HEADERS) {
n = LWS_HTTP2_FRAME_TYPE_HEADERS;
flags = LWS_HTTP2_FLAGS__HEADER__END_HEADER;
flags = LWS_HTTP2_FLAG_END_HEADERS;
}
return lws_http2_frame_write(wsi, n, flags, wsi->u.http2.my_stream_id, len, buf);
}

View file

@ -608,12 +608,19 @@ enum lws_http2_wellknown_frame_types {
LWS_HTTP2_FRAME_TYPE_COUNT /* always last */
};
enum lws_http2_flags {
LWS_HTTP2_FLAG_END_STREAM = 1,
LWS_HTTP2_FLAG_END_HEADERS = 4,
LWS_HTTP2_FLAG_PADDED = 8,
LWS_HTTP2_FLAG_PRIORITY = 0x20,
LWS_HTTP2_FLAG_SETTINGS_ACK = 1,
};
#define LWS_HTTP2_STREAM_ID_MASTER 0
#define LWS_HTTP2_FRAME_HEADER_LENGTH 9
#define LWS_HTTP2_SETTINGS_LENGTH 6
#define LWS_HTTP2_FLAGS__HEADER__END_HEADER 4
struct http2_settings {
unsigned int setting[LWS_HTTP2_SETTINGS__COUNT];
};
@ -661,6 +668,9 @@ struct _lws_http2_related {
unsigned char type;
unsigned char flags;
unsigned char frame_state;
unsigned int END_STREAM:1;
unsigned int END_HEADERS:1;
/* hpack */
enum http2_hpack_state hpack;
@ -862,6 +872,7 @@ libwebsockets_generate_client_handshake(struct libwebsocket_context *context,
LWS_EXTERN int
lws_handle_POLLOUT_event(struct libwebsocket_context *context,
struct libwebsocket *wsi, struct libwebsocket_pollfd *pollfd);
/*
* EXTENSIONS
*/

View file

@ -640,6 +640,32 @@ libwebsocket_create_new_server_wsi(struct libwebsocket_context *context)
return new_wsi;
}
/**
* lws_http_transaction_completed() - wait for new http transaction or close
* @wsi: websocket connection
*
* Returns 1 if the HTTP connection must close now
* Returns 0 and resets connection to wait for new HTTP header /
* transaction if possible
*/
LWS_VISIBLE
int lws_http_transaction_completed(struct libwebsocket *wsi)
{
/* if we can't go back to accept new headers, drop the connection */
if (wsi->u.http.connection_type != HTTP_CONNECTION_KEEP_ALIVE) {
lwsl_info("%s: close connection\n", __func__);
return 1;
}
/* otherwise set ourselves up ready to go again */
wsi->state = WSI_STATE_HTTP;
lwsl_info("%s: await new transaction\n", __func__);
return 0;
}
int lws_server_socket_service(struct libwebsocket_context *context,
struct libwebsocket *wsi, struct libwebsocket_pollfd *pollfd)
{
@ -739,8 +765,9 @@ try_pollout:
break;
}
/* nonzero for completion or error */
if (libwebsockets_serve_http_file_fragment(context, wsi))
/* >0 == completion, <0 == error */
n = libwebsockets_serve_http_file_fragment(context, wsi);
if (n < 0 || (n > 0 && lws_http_transaction_completed(wsi)))
libwebsocket_close_and_free_session(context, wsi,
LWS_CLOSE_STATUS_NOSTATUS);
break;
@ -1026,7 +1053,8 @@ LWS_VISIBLE int libwebsockets_return_http_status(
* local files down the http link in a single step.
*
* Returning <0 indicates error and the wsi should be closed. Returning
* >0 indicates the file was completely sent and the wsi should be closed.
* >0 indicates the file was completely sent and
* lws_http_transaction_completed() called on the wsi (and close if != 0)
* ==0 indicates the file transfer is started and needs more service later,
* the wsi should be left alone.
*/
@ -1055,14 +1083,14 @@ LWS_VISIBLE int libwebsockets_serve_http_file(
}
if (lws_add_http_header_status(context, wsi, 200, &p, end))
return 1;
return -1;
if (lws_add_http_header_by_token(context, wsi, WSI_TOKEN_HTTP_SERVER, (unsigned char *)"libwebsockets", 13, &p, end))
return 1;
return -1;
if (lws_add_http_header_by_token(context, wsi, WSI_TOKEN_HTTP_CONTENT_TYPE, (unsigned char *)content_type, strlen(content_type), &p, end))
return 1;
return -1;
n = sprintf((char *)clen, "%lu", (unsigned long)wsi->u.http.filelen);
if (lws_add_http_header_by_token(context, wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH, clen, n, &p, end))
return 1;
return -1;
if (other_headers) {
if ((end - p) < other_headers_len)
@ -1072,7 +1100,7 @@ LWS_VISIBLE int libwebsockets_serve_http_file(
}
if (lws_finalize_http_header(context, wsi, &p, end))
return 1;
return -1;
ret = libwebsocket_write(wsi, response,
p - response, LWS_WRITE_HTTP_HEADERS);

View file

@ -182,14 +182,14 @@ static int callback_http(struct libwebsocket_context *context,
if (len < 1) {
libwebsockets_return_http_status(context, wsi,
HTTP_STATUS_BAD_REQUEST, NULL);
return -1;
goto try_to_reuse;
}
/* this example server has no concept of directories */
if (strchr((const char *)in + 1, '/')) {
libwebsockets_return_http_status(context, wsi,
HTTP_STATUS_FORBIDDEN, NULL);
return -1;
goto try_to_reuse;
}
/* if a legal POST URL, let it continue and accept data */
@ -306,9 +306,10 @@ static int callback_http(struct libwebsocket_context *context,
other_headers = leaf_path;
}
if (libwebsockets_serve_http_file(context, wsi, buf,
mimetype, other_headers, n))
return -1; /* through completion or error, close the socket */
n = libwebsockets_serve_http_file(context, wsi, buf,
mimetype, other_headers, n);
if (n < 0 || ((n > 0) && lws_http_transaction_completed(wsi)))
return -1; /* error or can't reuse connection: close the socket */
/*
* notice that the sending of the file completes asynchronously,
@ -331,16 +332,15 @@ static int callback_http(struct libwebsocket_context *context,
case LWS_CALLBACK_HTTP_BODY_COMPLETION:
lwsl_notice("LWS_CALLBACK_HTTP_BODY_COMPLETION\n");
/* the whole of the sent body arried, close the connection */
/* the whole of the sent body arrived, close or reuse the connection */
libwebsockets_return_http_status(context, wsi,
HTTP_STATUS_OK, NULL);
return -1;
goto try_to_reuse;
case LWS_CALLBACK_HTTP_FILE_COMPLETION:
// lwsl_info("LWS_CALLBACK_HTTP_FILE_COMPLETION seen\n");
/* kill the connection after we sent one file */
return -1;
goto try_to_reuse;
case LWS_CALLBACK_HTTP_WRITEABLE:
/*
@ -386,6 +386,8 @@ flush_bail:
libwebsocket_callback_on_writable(context, wsi);
break;
}
close(pss->fd);
goto try_to_reuse;
bail:
close(pss->fd);
@ -475,6 +477,12 @@ bail:
}
return 0;
try_to_reuse:
if (lws_http_transaction_completed(wsi))
return -1;
return 0;
}