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, int curl_push_callback(CURL *parent,
CURL *easy, CURL *easy,
int num_headers, size_t num_headers,
struct curl_pushheaders *headers, struct curl_pushheaders *headers,
void *userp); void *userp);

View File

@ -302,10 +302,14 @@ struct curl_headerpair {
}; };
struct curl_pushheaders; /* forward declaration only */ 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, typedef int (*curl_push_callback)(CURL *parent,
CURL *easy, CURL *easy,
int num_headers, size_t num_headers,
struct curl_pushheaders *headers, struct curl_pushheaders *headers,
void *userp); void *userp);

View File

@ -33,6 +33,7 @@
#include "rawstr.h" #include "rawstr.h"
#include "multiif.h" #include "multiif.h"
#include "conncache.h" #include "conncache.h"
#include "url.h"
/* The last #include files should be: */ /* The last #include files should be: */
#include "curl_memory.h" #include "curl_memory.h"
@ -205,6 +206,71 @@ static ssize_t send_callback(nghttp2_session *h2,
return written; 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, static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
void *userp) void *userp)
{ {
@ -292,12 +358,14 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
Curl_expire(data_s, 1); Curl_expire(data_s, 1);
break; break;
case NGHTTP2_PUSH_PROMISE: case NGHTTP2_PUSH_PROMISE:
DEBUGF(infof(data_s, "Got PUSH_PROMISE, RST_STREAM it!\n")); rv = push_promise(data_s, &frame->push_promise);
rv = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE, if(rv) { /* deny! */
frame->push_promise.promised_stream_id, rv = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE,
NGHTTP2_CANCEL); frame->push_promise.promised_stream_id,
if(nghttp2_is_fatal(rv)) { NGHTTP2_CANCEL);
return rv; if(nghttp2_is_fatal(rv)) {
return rv;
}
} }
break; break;
case NGHTTP2_SETTINGS: case NGHTTP2_SETTINGS:

View File

@ -62,8 +62,6 @@
#define GOOD_MULTI_HANDLE(x) \ #define GOOD_MULTI_HANDLE(x) \
((x) && (((struct Curl_multi *)(x))->type == CURL_MULTI_HANDLE)) ((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, static void singlesocket(struct Curl_multi *multi,
struct SessionHandle *data); struct SessionHandle *data);
@ -2341,6 +2339,12 @@ CURLMcode curl_multi_setopt(CURLM *multi_handle,
case CURLMOPT_SOCKETDATA: case CURLMOPT_SOCKETDATA:
multi->socket_userp = va_arg(param, void *); multi->socket_userp = va_arg(param, void *);
break; 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: case CURLMOPT_PIPELINING:
multi->pipelining = va_arg(param, long); multi->pipelining = va_arg(param, long);
break; break;

View File

@ -87,6 +87,10 @@ struct Curl_multi {
curl_socket_callback socket_cb; curl_socket_callback socket_cb;
void *socket_userp; void *socket_userp;
/* callback function and user data pointer for server push */
curl_push_callback push_cb;
void *push_userp;
/* Hostname cache */ /* Hostname cache */
struct curl_hash hostcache; struct curl_hash hostcache;

View File

@ -198,6 +198,8 @@
#define HEADERSIZE 256 #define HEADERSIZE 256
#define CURLEASY_MAGIC_NUMBER 0xc0dedbadU #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. /* Some convenience macros to get the larger/smaller value out of two given.
We prefix with CURL to prevent name collisions. */ We prefix with CURL to prevent name collisions. */