Commit ea7134ac authored by Daniel Stenberg's avatar Daniel Stenberg
Browse files

http2: initial implementation of the push callback

parent 70191958
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
@@ -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);


+5 −1
Original line number Original line Diff line number Diff line
@@ -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);


+74 −6
Original line number Original line Diff line number Diff line
@@ -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,13 +358,15 @@ 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);
    if(rv) { /* deny! */
      rv = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE,
      rv = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE,
                                     frame->push_promise.promised_stream_id,
                                     frame->push_promise.promised_stream_id,
                                     NGHTTP2_CANCEL);
                                     NGHTTP2_CANCEL);
      if(nghttp2_is_fatal(rv)) {
      if(nghttp2_is_fatal(rv)) {
        return rv;
        return rv;
      }
      }
    }
    break;
    break;
  case NGHTTP2_SETTINGS:
  case NGHTTP2_SETTINGS:
  {
  {
+6 −2
Original line number Original line Diff line number Diff line
@@ -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;
+4 −0
Original line number Original line Diff line number Diff line
@@ -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;


Loading