summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Stenberg <daniel@haxx.se>2015-06-01 15:52:46 +0200
committerDaniel Stenberg <daniel@haxx.se>2015-06-24 23:44:42 +0200
commitf65ab8864e2f9d580daf0ca48c972d6124a2ff3d (patch)
treebaa0c14a5de151b3c48df583be255b57986fc41b
parentfeea9263e9066768323a759ee178c144fccf5998 (diff)
downloadcurl-f65ab8864e2f9d580daf0ca48c972d6124a2ff3d.tar.gz
http2: fixed the header accessor functions for the push callback
-rw-r--r--docs/libcurl/opts/CURLMOPT_PUSHFUNCTION.321
-rw-r--r--include/curl/multi.h17
-rw-r--r--lib/http.c4
-rw-r--r--lib/http.h5
-rw-r--r--lib/http2.c78
5 files changed, 82 insertions, 43 deletions
diff --git a/docs/libcurl/opts/CURLMOPT_PUSHFUNCTION.3 b/docs/libcurl/opts/CURLMOPT_PUSHFUNCTION.3
index a46150ab7..0e4e3326e 100644
--- a/docs/libcurl/opts/CURLMOPT_PUSHFUNCTION.3
+++ b/docs/libcurl/opts/CURLMOPT_PUSHFUNCTION.3
@@ -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,
diff --git a/include/curl/multi.h b/include/curl/multi.h
index 5b462adc8..b2670e254 100644
--- a/include/curl/multi.h
+++ b/include/curl/multi.h
@@ -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,
diff --git a/lib/http.c b/lib/http.c
index d307eabd5..f64a56546 100644
--- a/lib/http.c
+++ b/lib/http.c
@@ -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
diff --git a/lib/http.h b/lib/http.h
index 80ec68303..63ea4ace4 100644
--- a/lib/http.h
+++ b/lib/http.h
@@ -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
};
diff --git a/lib/http2.c b/lib/http2.c
index 8f5b6930b..674a39c09 100644
--- a/lib/http2.c
+++ b/lib/http2.c
@@ -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;
}