1
0
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:
Daniel Stenberg 2015-06-01 11:45:52 +02:00
parent 70191958b5
commit ea7134ac87
6 changed files with 92 additions and 10 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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,13 +358,15 @@ 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 = 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:
{

View File

@ -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;

View File

@ -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;

View File

@ -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. */