mirror of
https://github.com/moparisthebest/curl
synced 2024-12-21 23:58:49 -05:00
http2: initial implementation of the push callback
This commit is contained in:
parent
70191958b5
commit
ea7134ac87
@ -39,7 +39,7 @@ struct curl_headerpair *curl_pushheader_byname(push_headers, char *name);
|
||||
|
||||
int curl_push_callback(CURL *parent,
|
||||
CURL *easy,
|
||||
int num_headers,
|
||||
size_t num_headers,
|
||||
struct curl_pushheaders *headers,
|
||||
void *userp);
|
||||
|
||||
|
@ -302,10 +302,14 @@ struct curl_headerpair {
|
||||
};
|
||||
|
||||
struct curl_pushheaders; /* forward declaration only */
|
||||
struct curl_headerpair *curl_pushheader_bynum(struct curl_pushheaders *h,
|
||||
int num);
|
||||
struct curl_headerpair *curl_pushheader_byname(struct curl_pushheaders *h,
|
||||
char *name);
|
||||
|
||||
typedef int (*curl_push_callback)(CURL *parent,
|
||||
CURL *easy,
|
||||
int num_headers,
|
||||
size_t num_headers,
|
||||
struct curl_pushheaders *headers,
|
||||
void *userp);
|
||||
|
||||
|
80
lib/http2.c
80
lib/http2.c
@ -33,6 +33,7 @@
|
||||
#include "rawstr.h"
|
||||
#include "multiif.h"
|
||||
#include "conncache.h"
|
||||
#include "url.h"
|
||||
|
||||
/* The last #include files should be: */
|
||||
#include "curl_memory.h"
|
||||
@ -205,6 +206,71 @@ static ssize_t send_callback(nghttp2_session *h2,
|
||||
return written;
|
||||
}
|
||||
|
||||
|
||||
/* We pass a pointer to this struct in the push callback, but the contents of
|
||||
the struct are hidden from the user. */
|
||||
struct curl_pushheaders {
|
||||
struct SessionHandle *data;
|
||||
const nghttp2_push_promise *frame;
|
||||
};
|
||||
|
||||
/*
|
||||
* push header access function. Only to be used from within the push callback
|
||||
*/
|
||||
struct curl_headerpair *curl_pushheader_bynum(struct curl_pushheaders *h,
|
||||
int num)
|
||||
{
|
||||
/* Verify that we got a good easy handle in the push header struct, mostly to
|
||||
detect rubbish input fast(er). */
|
||||
if(!h || !GOOD_EASY_HANDLE(h->data))
|
||||
return NULL;
|
||||
(void)num;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int push_promise(struct SessionHandle *data,
|
||||
const nghttp2_push_promise *frame)
|
||||
{
|
||||
int rv;
|
||||
if(data->multi->push_cb) {
|
||||
/* clone the parent */
|
||||
CURL *newhandle = curl_easy_duphandle(data);
|
||||
if(!newhandle) {
|
||||
infof(data, "failed to duplicate handle\n");
|
||||
rv = 1; /* FAIL HARD */
|
||||
}
|
||||
else {
|
||||
struct curl_pushheaders heads;
|
||||
heads.data = data;
|
||||
heads.frame = frame;
|
||||
/* ask the application */
|
||||
DEBUGF(infof(data, "Got PUSH_PROMISE, ask application!\n"));
|
||||
rv = data->multi->push_cb(data, newhandle,
|
||||
frame->nvlen, &heads,
|
||||
data->multi->push_userp);
|
||||
if(rv)
|
||||
/* denied, kill off the new handle again */
|
||||
(void)Curl_close(newhandle);
|
||||
else {
|
||||
/* approved, add to the multi handle */
|
||||
CURLMcode rc = curl_multi_add_handle(data->multi, newhandle);
|
||||
if(rc) {
|
||||
infof(data, "failed to add handle to multi\n");
|
||||
Curl_close(newhandle);
|
||||
rv = 1;
|
||||
}
|
||||
else
|
||||
rv = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
DEBUGF(infof(data, "Got PUSH_PROMISE, ignore it!\n"));
|
||||
rv = 1;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
|
||||
void *userp)
|
||||
{
|
||||
@ -292,12 +358,14 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
|
||||
Curl_expire(data_s, 1);
|
||||
break;
|
||||
case NGHTTP2_PUSH_PROMISE:
|
||||
DEBUGF(infof(data_s, "Got PUSH_PROMISE, RST_STREAM it!\n"));
|
||||
rv = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE,
|
||||
frame->push_promise.promised_stream_id,
|
||||
NGHTTP2_CANCEL);
|
||||
if(nghttp2_is_fatal(rv)) {
|
||||
return rv;
|
||||
rv = push_promise(data_s, &frame->push_promise);
|
||||
if(rv) { /* deny! */
|
||||
rv = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE,
|
||||
frame->push_promise.promised_stream_id,
|
||||
NGHTTP2_CANCEL);
|
||||
if(nghttp2_is_fatal(rv)) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case NGHTTP2_SETTINGS:
|
||||
|
@ -62,8 +62,6 @@
|
||||
|
||||
#define GOOD_MULTI_HANDLE(x) \
|
||||
((x) && (((struct Curl_multi *)(x))->type == CURL_MULTI_HANDLE))
|
||||
#define GOOD_EASY_HANDLE(x) \
|
||||
((x) && (((struct SessionHandle *)(x))->magic == CURLEASY_MAGIC_NUMBER))
|
||||
|
||||
static void singlesocket(struct Curl_multi *multi,
|
||||
struct SessionHandle *data);
|
||||
@ -2341,6 +2339,12 @@ CURLMcode curl_multi_setopt(CURLM *multi_handle,
|
||||
case CURLMOPT_SOCKETDATA:
|
||||
multi->socket_userp = va_arg(param, void *);
|
||||
break;
|
||||
case CURLMOPT_PUSHFUNCTION:
|
||||
multi->push_cb = va_arg(param, curl_push_callback);
|
||||
break;
|
||||
case CURLMOPT_PUSHDATA:
|
||||
multi->push_userp = va_arg(param, void *);
|
||||
break;
|
||||
case CURLMOPT_PIPELINING:
|
||||
multi->pipelining = va_arg(param, long);
|
||||
break;
|
||||
|
@ -87,6 +87,10 @@ struct Curl_multi {
|
||||
curl_socket_callback socket_cb;
|
||||
void *socket_userp;
|
||||
|
||||
/* callback function and user data pointer for server push */
|
||||
curl_push_callback push_cb;
|
||||
void *push_userp;
|
||||
|
||||
/* Hostname cache */
|
||||
struct curl_hash hostcache;
|
||||
|
||||
|
@ -198,6 +198,8 @@
|
||||
#define HEADERSIZE 256
|
||||
|
||||
#define CURLEASY_MAGIC_NUMBER 0xc0dedbadU
|
||||
#define GOOD_EASY_HANDLE(x) \
|
||||
((x) && (((struct SessionHandle *)(x))->magic == CURLEASY_MAGIC_NUMBER))
|
||||
|
||||
/* Some convenience macros to get the larger/smaller value out of two given.
|
||||
We prefix with CURL to prevent name collisions. */
|
||||
|
Loading…
Reference in New Issue
Block a user