]> granicus.if.org Git - curl/commitdiff
http2: fixed the header accessor functions for the push callback
authorDaniel Stenberg <daniel@haxx.se>
Mon, 1 Jun 2015 13:52:46 +0000 (15:52 +0200)
committerDaniel Stenberg <daniel@haxx.se>
Wed, 24 Jun 2015 21:44:42 +0000 (23:44 +0200)
docs/libcurl/opts/CURLMOPT_PUSHFUNCTION.3
include/curl/multi.h
lib/http.c
lib/http.h
lib/http2.c

index a46150ab71009e8f267830908947dbc7b9ce53e5..0e4e3326e204bc2c5bf9f9cc0307c6e7060a80e4 100644 (file)
@@ -27,15 +27,8 @@ CURLMOPT_PUSHFUNCTION \- approve or deny server pushes
 .nf
 #include <curl/curl.h>
 
-struct curl_headerpair {
-   unsigned char *name;   /* zero terminated name */
-   size_t namelen;        /* length of 'name' */
-   unsigned char *value;  /* zero terminated name */
-   size_t valuelen;       /* length of 'value' */
-};
-
-struct curl_headerpair *curl_pushheader_bynum(push_headers, int num);
-struct curl_headerpair *curl_pushheader_byname(push_headers, char *name);
+char *curl_pushheader_bynum(push_headers, int num);
+char *curl_pushheader_byname(push_headers, char *name);
 
 int curl_push_callback(CURL *parent,
                        CURL *easy,
@@ -78,12 +71,12 @@ functions. These functions can only be used from within this callback and they
 can only access the PUSH_PROMISE headers. The normal response headers will be
 pased to the header callback for pushed streams just as for normal streams.
 .IP curl_pushheader_bynum
-Returns the header pair at index 'num' (or NULL). The returned pointer points
-to a struct that will be freed when this callback returns.
+Returns the header at index 'num' (or NULL). The returned pointer points
+to a "name:value" string that will be freed when this callback returns.
 .IP curl_pushheader_byname
-Returns the header pair for the given header name (or NULL). This is a
-shortcut so that the application doesn't have to loop through all headers to
-find the one it is interested in.
+Returns the value for the given header name (or NULL). This is a shortcut so
+that the application doesn't have to loop through all headers to find the one
+it is interested in.
 .SH CALLBACK RETURN VALUE
 .IP "CURL_PUSH_OK (0)"
 The application has accepted the stream and it can now start receiving data,
index 5b462adc8105b73f73dbb0327030fba9df223da9..b2670e2547e6b2abf22bf84c456d27e2c96382bc 100644 (file)
@@ -294,18 +294,13 @@ typedef int (*curl_multi_timer_callback)(CURLM *multi,    /* multi handle */
 #define CURL_PUSH_OK   0
 #define CURL_PUSH_DENY 1
 
-struct curl_headerpair {
-   unsigned char *name;   /* zero terminated name */
-   size_t namelen;        /* length of 'name' */
-   unsigned char *value;  /* zero terminated name */
-   size_t valuelen;       /* length of 'value' */
-};
-
 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);
+
+CURL_EXTERN char *curl_pushheader_bynum(struct curl_pushheaders *h,
+                                        size_t num);
+
+CURL_EXTERN char *curl_pushheader_byname(struct curl_pushheaders *h,
+                                         char *name);
 
 typedef int (*curl_push_callback)(CURL *parent,
                                   CURL *easy,
index d307eabd55f5cecccd7ee6142e0d3752eebac234..f64a56546937ba98c579fdd12d3cee3188d82a33 100644 (file)
@@ -176,6 +176,8 @@ static CURLcode http_disconnect(struct connectdata *conn, bool dead_connection)
   if(http) {
     Curl_add_buffer_free(http->header_recvbuf);
     http->header_recvbuf = NULL; /* clear the pointer */
+    free(http->push_headers);
+    http->push_headers = NULL;
   }
 #else
   (void)conn;
@@ -1492,6 +1494,8 @@ CURLcode Curl_http_done(struct connectdata *conn,
     DEBUGF(infof(data, "free header_recvbuf!!\n"));
     Curl_add_buffer_free(http->header_recvbuf);
     http->header_recvbuf = NULL; /* clear the pointer */
+    free(http->push_headers);
+    http->push_headers = NULL;
   }
 #endif
 
index 80ec68303d4aec2511405e72206eb9489240db5b..63ea4ace4848681f1863f4bd8ee04d5080396363 100644 (file)
@@ -176,7 +176,10 @@ struct HTTP {
   const uint8_t *upload_mem; /* points to a buffer to read from */
   size_t upload_len; /* size of the buffer 'upload_mem' points to */
   curl_off_t upload_left; /* number of bytes left to upload */
-  Curl_send_buffer *push_recvbuf; /* store incoming push headers */
+
+  char **push_headers;       /* allocated array */
+  size_t push_headers_used;  /* number of entries filled in */
+  size_t push_headers_alloc; /* number of entries allocated */
 #endif
 };
 
index 8f5b6930b69eeae44eb1e002f305f9faec1fac7d..674a39c09aeec708e1b67ab2e041fb333c29dc2a 100644 (file)
@@ -219,14 +219,42 @@ struct curl_pushheaders {
 /*
  * 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)
+char *curl_pushheader_bynum(struct curl_pushheaders *h, size_t 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;
+  else {
+    struct HTTP *stream = h->data->req.protop;
+    if(num < stream->push_headers_used)
+      return stream->push_headers[num];
+  }
+  return NULL;
+}
+
+/*
+ * push header access function. Only to be used from within the push callback
+ */
+char *curl_pushheader_byname(struct curl_pushheaders *h, char *header)
+{
+  /* 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) || !header)
+    return NULL;
+  else {
+    struct HTTP *stream = h->data->req.protop;
+    size_t len = strlen(header);
+    size_t i;
+    for(i=0; i<stream->push_headers_used; i++) {
+      if(!strncmp(header, stream->push_headers[i], len)) {
+        /* sub-match, make sure that it us followed by a colon */
+        if(stream->push_headers[i][len] != ':')
+          continue;
+        return &stream->push_headers[i][len+1];
+      }
+    }
+  }
   return NULL;
 }
 
@@ -283,13 +311,14 @@ static int push_promise(struct SessionHandle *data,
 
     stream = data->req.protop;
 
-#ifdef CURLDEBUG
-    fprintf(stderr, "PUSHHDR %s\n", stream->push_recvbuf->buffer);
-#endif
-
     rv = data->multi->push_cb(data, newhandle,
-                              frame->nvlen, &heads,
+                              stream->push_headers_used, &heads,
                               data->multi->push_userp);
+
+    /* free the headers array again */
+    free(stream->push_headers);
+    stream->push_headers = NULL;
+
     if(rv) {
       /* denied, kill off the new handle again */
       (void)Curl_close(newhandle);
@@ -667,15 +696,30 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
   /* Store received PUSH_PROMISE headers to be used when the subsequent
      PUSH_PROMISE callback comes */
   if(frame->hd.type == NGHTTP2_PUSH_PROMISE) {
-    fprintf(stderr, "*** PUSH_PROMISE headers on stream %u for %u\n",
-            stream_id,
-            frame->push_promise.promised_stream_id);
-    if(!stream->push_recvbuf)
-      stream->push_recvbuf = Curl_add_buffer_init();
-    Curl_add_buffer(stream->push_recvbuf, name, namelen);
-    Curl_add_buffer(stream->push_recvbuf, ":", 1);
-    Curl_add_buffer(stream->push_recvbuf, value, valuelen);
-    Curl_add_buffer(stream->push_recvbuf, "\r\n", 2);
+    char *h;
+
+    if(!stream->push_headers) {
+      stream->push_headers_alloc = 10;
+      stream->push_headers = malloc(stream->push_headers_alloc *
+                                    sizeof(char *));
+      stream->push_headers_used = 0;
+    }
+    else if(stream->push_headers_used ==
+            stream->push_headers_alloc) {
+      char **headp;
+      stream->push_headers_alloc *= 2;
+      headp = realloc(stream->push_headers,
+                      stream->push_headers_alloc * sizeof(char *));
+      if(!headp) {
+        free(stream->push_headers);
+        stream->push_headers = NULL;
+        return 1;
+      }
+      stream->push_headers = headp;
+    }
+    h = aprintf("%s:%s", name, value);
+    if(h)
+      stream->push_headers[stream->push_headers_used++] = h;
     return 0;
   }